Skip to content

fix(onboard): measure the host reuse window from collection completion - #10733

Open
Dongni-Yang wants to merge 6 commits into
mainfrom
fix/10670-preflight-capability-collapse
Open

fix(onboard): measure the host reuse window from collection completion#10733
Dongni-Yang wants to merge 6 commits into
mainfrom
fix/10670-preflight-capability-collapse

Conversation

@Dongni-Yang

@Dongni-Yang Dongni-Yang commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Outcome

When successful host and GPU probes take longer than the 30-second reuse window, onboarding no longer reports every required capability as unconfirmed. It still rejects stale, invalid, or out-of-order timing evidence. The failure output now prints bounded evidence for an inconclusive host projection.

Reason

assertOnboardHostReadiness used the caller's observation-start timestamp as both provenance and collection completion. Slow probes therefore aged out the facts they had just collected. Separating those timestamps also required preserving fail-closed behavior when the clock moves backward or a caller supplies invalid timing metadata.

Related issues

Closes #10670
Refs #10734

Changes

  • Preserve observedAt as provenance and measure host-fact freshness from collection completion.
  • Stamp collection completion after host and GPU probes during fresh onboarding.
  • At both cached-resume checkpoints, stamp collection completion before the gateway wait.
  • Reject invalid or out-of-order collection timestamps through the existing host.probe.failure path without emitting invalid provenance.
  • Print approved host failure or stale evidence beside an unconfirmed capability list.
  • Keep the macOS advisory predicate and wording unchanged. [macOS][Onboard] headless_remote_hint prints Linux-only remediation text on macOS #10734 tracks that separate product decision; fix(advisories): keep the headless remote hint platform-neutral #10738 is not part of this PR.
  • Add behavior tests for slow healthy probes, post-collection delay, invalid and reversed timestamps, fresh onboarding, both resume checkpoints, and bounded diagnostics.

Verification

  • npx vitest run --project cli src/lib/onboard/fatal-runtime-preflight.test.ts src/lib/onboard/machine/handlers/preflight.test.ts — 47 passed.
  • npx vitest run --project cli src/lib/readiness src/lib/onboard/fatal-runtime-preflight.test.ts src/lib/onboard/machine src/lib/onboard/preflight.test.ts — 1,331 passed across 85 files.
  • npx vitest run --project integration test/automation/pull-requests/growth-guardrails.test.ts — 33 passed.
  • npm run source-shape:check — passed with no source-shape tests and all registered exceptions valid.
  • npm run checks:repository — passed.
  • npm run typecheck:cli — passed.
  • npx oxlint and Oxfmt checks on the four changed files — passed.
  • git diff --check — passed.
  • npm run validate:pr — passed.
  • The four-file diff contains no secrets, API keys, or credentials.
  • Documentation review: no-docs-needed
  • Documentation evidence: Independently reviewed the readiness timing and diagnostic changes against the current System Readiness documentation. The documented completion-based reuse window, fail-closed timing behavior, and bounded evidence contract remain accurate.
  • Documentation agent: GPT-5
  • Targeted validation: 47 focused onboarding tests, 1,331 readiness/onboarding tests, and 33 growth-guardrail tests passed.
  • Broad gate: passed — npm run validate:pr passed.

Review notes

The accepted scope is the #10670 timing defect. The platform-specific advisory wording or gating choice remains separate in #10734 and #10738.

An independent correctness, documentation, and nine-category security review passed after the timestamp-ordering repair. No live E2E is needed for this deterministic clock and projection boundary. Repository-owned review and merge gates still apply.


Signed-off-by: Dongni Yang dongniy@nvidia.com

Summary by CodeRabbit

  • Bug Fixes
    • Improved onboarding readiness validation by distinguishing when system information was observed from when collection completed.
    • Prevented false stale-readiness failures during host and GPU checks.
    • Improved handling and diagnostics for invalid, out-of-order, delayed, or stale readiness timestamps.
    • Ensured gateway wait periods are measured from completed evidence collection.

`assertOnboardHostReadiness` drove `collectHostObservations` with a clock
pinned to the caller's `observedAt`, so the snapshot's `completedAt` was
stamped before the host assessment it reports on had run. The reuse window
then measured the assessment's own duration. A host whose Docker probes took
longer than the 30-second window aged out facts that had just been gathered
successfully, and `projectHostReadiness` replaced every observation and
capability with `unknown`. Onboarding reported nine required capabilities as
unconfirmed on a host whose Docker daemon was installed, reachable and
supported.

#9325 established that the window starts when a collection finishes and
removed the same pinning from `collectOnboardHostReadiness`. It left the
`assertOnboardHostReadiness` seam, which fresh onboarding and both resume
checkpoints still use. `observedAt` is now provenance only: the collection
stamps its own completion, and the caller's start time is applied to the
snapshot afterwards.

Snapshot reuse still fails closed. `collectAdmittedReadinessPair` re-projects
a held snapshot against a later clock, and that path is unchanged.

Signed-off-by: Dongni Yang <dongniy@nvidia.com>
… list

When the host projection cannot evaluate a capability it files the reason as
evidence, `host.probe.failure` or `host.probe.stale`, and as a
warning-severity `host.probe.inconclusive` finding. Admission reports only
blocking findings, and `printReadinessFailure` takes only findings, so neither
reached the operator. A collapse printed a bare list of unconfirmed
capabilities, which reads as a Docker fault on a host whose Docker is healthy.

`assertOnboardSystemReadiness` now prints that evidence beside the capability
list, matching what `assertOnboardGatewayReadiness` already does for the
gateway projection. #9325 recorded the measured age and the applied window on
`host.probe.stale` for this purpose; no caller printed them until now.

Signed-off-by: Dongni Yang <dongniy@nvidia.com>
@coderabbitai

coderabbitai Bot commented Sep 1, 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: 03d49e98-5e33-4f7b-943c-7abb7805c357

📥 Commits

Reviewing files that changed from the base of the PR and between dcb7b7d and c9da1b6.

📒 Files selected for processing (4)
  • src/lib/onboard/fatal-runtime-preflight.test.ts
  • src/lib/onboard/fatal-runtime-preflight.ts
  • src/lib/onboard/machine/handlers/preflight.test.ts
  • src/lib/onboard/machine/handlers/preflight.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/lib/onboard/machine/handlers/preflight.ts
  • src/lib/onboard/fatal-runtime-preflight.ts
  • src/lib/onboard/fatal-runtime-preflight.test.ts
  • src/lib/onboard/machine/handlers/preflight.test.ts

Included review availability: Your plan provides up to 12 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

Runtime preflight now separates host observation provenance from collection completion time. Freshness checks use collection completion time. Readiness failures report filtered host or gateway evidence. Tests cover timestamp validation, timing, and diagnostics.

Changes

Runtime preflight

Layer / File(s) Summary
Observation freshness
src/lib/onboard/fatal-runtime-preflight.ts, src/lib/onboard/machine/handlers/preflight.ts
Host readiness accepts collectedAt separately from observedAt. Host collection validates timestamp values and ordering.
Resume preflight timestamp wiring
src/lib/onboard/machine/handlers/preflight.ts, src/lib/onboard/machine/handlers/preflight.test.ts
Resume preflight records timestamps before gateway waiting and after refreshed host assessment. Tests verify probe duration and gateway delay.
Readiness evidence reporting and validation
src/lib/onboard/fatal-runtime-preflight.ts, src/lib/onboard/fatal-runtime-preflight.test.ts
System and gateway failures use filtered actionable evidence. Tests verify stale-host diagnostics, invalid timestamps, fresh onboarding timing, and unconfirmed capabilities.

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

Merge Risk: ⚪ Minimal · up to c9da1

This localized onboarding timing change preserves fail-closed handling while correcting freshness measurement and adding bounded diagnostics; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant RuntimePreflight
  participant HostCollection
  participant GPUProbe
  participant ReadinessValidation
  RuntimePreflight->>HostCollection: record observedAt
  HostCollection->>GPUProbe: run host and GPU probes
  GPUProbe-->>HostCollection: return refreshed host facts
  HostCollection-->>RuntimePreflight: return collectedAt
  RuntimePreflight->>ReadinessValidation: validate observedAt and collectedAt
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: measuring the host reuse window from collection completion.
Linked Issues check ✅ Passed The changes address issue [#10670] by preventing successful but slow host and GPU probes from being marked stale, preserving fail-closed timestamp validation, and improving bounded readiness evidence …
Out of Scope Changes check ✅ Passed The changes remain within scope. They update host-readiness timing, diagnostics, onboarding resume paths, and related tests.
Full details: Linked Issues check

Explanation

The changes address issue [#10670] by preventing successful but slow host and GPU probes from being marked stale, preserving fail-closed timestamp validation, and improving bounded readiness evidence for accurate capability reporting.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/10670-preflight-capability-collapse

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

@github-code-quality

github-code-quality Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall line coverage in commit 25bee42 in the fix/10670-preflight-... branch remains at 96%, unchanged from commit 9169ab0 in the main branch.

TypeScript / code-coverage/cli

The overall line coverage in commit 25bee42 in the fix/10670-preflight-... branch remains at 84%, unchanged from commit 9169ab0 in the main branch.

Show a line coverage summary of the most impacted files.
File main 9169ab0 fix/10670-preflight-... 25bee42 +/-
src/lib/onboard...uild-context.ts 74% 74% 0%
src/lib/onboard...rs/preflight.ts 100% 100% 0%
src/lib/sandbox...rce-identity.ts 82% 82% 0%
src/lib/state/m...ck/decisions.ts 100% 100% 0%
src/lib/onboard...me-preflight.ts 79% 81% +2%

Updated September 01, 2026 15:00 UTC

Anchoring the reuse window to `collectHostObservations` alone overstated
freshness on the resume path. That caller assesses the host, detects the GPU,
then awaits gateway readiness before the host gate. Because it hands the gate
precomputed facts, the collector stamped completion after that await, so a slow
gateway collection left the host facts unbounded.

`assertOnboardHostReadiness` now accepts `collectedAt`, the moment the caller's
own probes finished, and applies it to the snapshot. The probes' duration is no
longer charged, which is the #10670 fix; everything after them still is. Both
resume checkpoints and fresh onboarding stamp it directly after their probes.

Replaces the cached-resume test that pinned the superseded rule. It required
rejection when `assessHost` outran the window, which production no longer does,
and it asserted that inside its own stub. It now pins the split the fix
depends on: the probe duration lands in `collectedAt`, the gateway wait after it.

Folds `printHostReadinessEvidence` and `printGatewayReadinessEvidence` into one
`printReadinessEvidence(evidence, ids)` with both id sets hoisted to module
scope, and states the host-evidence comment directly. Both from advisor review.

Signed-off-by: Dongni Yang <dongniy@nvidia.com>
@Dongni-Yang

Copy link
Copy Markdown
Contributor Author

Advisor findings for 52f0fd8, verified and grouped. Three accepted, one declined, four had no finding.

Behavior — blocker, accepted. Correct, and it is the sharper version of the bug this PR set out to fix. Anchoring the window to collectHostObservations alone overstates freshness wherever the caller hands the gate precomputed facts, because the collector then stamps completion for a collection it did not perform. The resume path does exactly that: assessHost(), detectGpuForReadiness(), then await assertGatewayReadiness() before the gate. The gateway wait was left unbounded.

Taken as specified — assertOnboardHostReadiness now accepts collectedAt, the moment the caller's own probes finished, and applies it to snapshot.completedAt. The probes' duration is not charged; everything after them is. Both resume checkpoints and fresh onboarding stamp it directly after their probes. observedAt stays provenance. Two tests pin the split: charges a delay between host collection and the gate (#10670) for the reject side, and the existing slow-collection test for the admit side.

Migration completion — accepted. rejects a cached resume when host collection exceeds the freshness window (#7411) did encode the replaced rule, and it asserted the rejection inside its own stub, so it passed against either implementation. Replaced with closes the cached resume host collection before the gateway wait (#10670), which pins the new contract at the handler boundary: collectedAt lands after the probes, the gateway wait after it. Verified red without the wiring.

Documentation — accepted. Comment reworded close to the suggestion.

Code reduction — accepted, over dependency-use's objection. The two loops were identical apart from the id set, and the gateway set was rebuilt on every failure. Folded into printReadinessEvidence(evidence, actionableEvidenceIds) with both sets hoisted to module scope. Dependency-use argued a shared renderer would not reduce ownership; I read that as an objection to introducing an abstraction layer, which this is not — the caller still supplies its own id set, so neither gate can widen the other's output. Both output tests still pass unchanged.

Design and architecture, test design, trust, operations — no finding. No action.

Verification after the changes: npm run typecheck:cli, npm run checks:repository, npx oxlint and npx oxfmt --check on all four changed files, and 1328 tests across 85 files in src/lib/readiness, src/lib/onboard/fatal-runtime-preflight.test.ts, src/lib/onboard/machine and src/lib/onboard/preflight.test.ts.

One note on CI: Build and validate the Pi candidate managed image (arm64) failed in 7 seconds on Set up Docker Buildx, before Node or any build step. This PR changes four TypeScript files and no Dockerfile, so I read that as runner infrastructure rather than the diff. Happy to be corrected.

Signed-off-by: Dongni Yang dongniy@nvidia.com

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor finished for commit 25bee42. Include the Advisor findings in the complete PR feedback collection. Verify and group valid findings before repair.

All previous runs

@github-actions github-actions Bot added v0.0.119 Release target and removed v0.0.118 labels Sep 1, 2026
@copy-pr-bot

copy-pr-bot Bot commented Sep 2, 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 Sep 2, 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.

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

Labels

v0.0.119 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[macOS][Onboard] one failed preflight sub-check reports every host capability as failed, including a working Docker daemon

2 participants