Skip to content

feat(cli): add type-safety hotspot report#2082

Merged
ericksoa merged 6 commits into
mainfrom
feat/type-safety-hotspots
Apr 20, 2026
Merged

feat(cli): add type-safety hotspot report#2082
ericksoa merged 6 commits into
mainfrom
feat/type-safety-hotspots

Conversation

@cv

@cv cv commented Apr 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a type-safety:hotspots developer command that ranks files and functions by type-safety ROI, then use it to refactor the first wave of high-value hotspots it surfaced. This gives contributors a repeatable way to prioritize typing work and knocks down the initial top five hotspots the new tool identified.

Changes

  • add scripts/type-safety-hotspots.ts and npm run type-safety:hotspots, plus tests covering hotspot scoring and @ts-nocheck detection
  • refactor the initial top five hotspots from the first report: src/lib/onboard-session.ts, src/lib/tiers.ts, src/lib/platform.ts, nemoclaw/src/commands/migration-state.ts, and src/lib/agent-defs.ts
  • add typed parsing/helpers to reduce unchecked JSON/YAML access, remove @ts-nocheck from tiers.ts and platform.ts, and add src/lib/agent-defs.test.ts
  • update test/policy-tiers.test.ts for the stricter nullable getTier() surface exposed by the new typing work
  • regenerate the touched troubleshooting skill artifact via the repo hooks
  • reduce the original hotspot scores reported by the new tool from 180/117/111/107/102 to 61/11/0/36/13 for onboard-session, tiers, platform, migration-state, and agent-defs

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)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make 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)

AI Disclosure

  • AI-assisted — tool: OpenAI Codex (pi coding agent)

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

Summary by CodeRabbit

  • Documentation
    • Clarified sandbox guidance for openclaw update, documenting cause and recommending rebuild/upgrade remediation that preserves workspace state.
  • Tests
    • Expanded coverage: agent manifests, platform/socket detection, migration-state env handling, session redaction, and type-safety analyzer/reporting.
  • Improvements
    • Hardened parsing/validation, stronger type/runtime checks, safer error handling, tighter session summaries, and refined platform/runtime detection.
  • Tools
    • Added a type-safety analysis CLI and an npm script to run it.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv self-assigned this Apr 20, 2026
@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d737733a-86aa-4409-8b80-71ecae20eb50

📥 Commits

Reviewing files that changed from the base of the PR and between 5eb8472 and 0c24d7f.

📒 Files selected for processing (2)
  • scripts/type-safety-hotspots.ts
  • test/type-safety-hotspots.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/type-safety-hotspots.ts

📝 Walkthrough

Walkthrough

Adds a TypeScript "type-safety hotspots" analysis CLI and tests; strengthens runtime parsing/validation across agent manifests, config/migration state, onboarding sessions, platform detection, and tiers; updates troubleshooting docs to warn that openclaw is pinned inside NemoClaw sandboxes and documents nemoclaw <name> rebuild remediation.

Changes

Cohort / File(s) Summary
Type-Safety Analysis
scripts/type-safety-hotspots.ts, package.json, test/type-safety-hotspots.test.ts
New TS analysis CLI and npm script type-safety:hotspots; walks project ASTs to detect weak-typing patterns, ranks hotspots by fan-in/exports/size, renders text/JSON reports; tests validate directive, parser-boundary, and ranking behavior using temp projects.
Config & Migration State
nemoclaw/src/commands/migration-state.ts, nemoclaw/src/commands/migration-state.test.ts
Introduced typed UnknownRecord readers/parsers for OpenClaw config, threaded env through path resolution, normalized workspace/external-roots handling, and added env-based path expansion test.
Agent Manifests & Definitions
src/lib/agent-defs.ts, src/lib/agent-defs.test.ts
YAML manifest parsing hardened via typed readers; validated typed accessors for fields; stricter port validation and computed properties; types for config and _legacy_paths tightened; added positive and negative unit tests.
Onboard Session & Locking
src/lib/onboard-session.ts, src/lib/onboard-session.test.ts
Replaced untyped step-status with StepStatus parsers and centralized shape readers; hardened errno handling in lock logic; added DebugSessionSummary with redaction; added test ensuring unsanitized failure tokens are redacted.
Platform & Runtime Detection
src/lib/platform.ts, test/platform.test.ts
Migrated to node:* imports, added typed interfaces for container/runtime/WSL/docker-host detection, tightened function signatures, refined socket-candidate logic (podman/colima), and added unsupported-platform podman test.
Tiers & Policy Validation
src/lib/tiers.ts, test/policy-tiers.test.ts
Typed parsing/validation of tiers.yaml into TierDefinition/TierPreset; functions now return typed results and validate override access values; tests refactored to use mustGetTier.
Docs / Troubleshooting
.agents/skills/nemoclaw-user-reference/references/troubleshooting.md, docs/reference/troubleshooting.md
Added guidance that NemoClaw bakes a pinned openclaw into sandbox images and that openclaw update may hang inside the sandbox; documented nemoclaw <name> rebuild (CLI-managed backup-and-restore) and Dockerfile.base update flow for source builds.

Sequence Diagram(s)

sequenceDiagram
  participant User as User (CLI)
  participant Script as type-safety-hotspots.ts
  participant TS as TypeScript Compiler API
  participant FS as File System
  participant Reporter as Report Renderer

  User->>Script: run CLI (args)
  Script->>FS: read tsconfig + source files
  Script->>TS: parse & type-check files
  TS-->>Script: ASTs + type info
  Script->>Script: analyze weak-typing, build graph, score hotspots
  Script->>Reporter: format text/JSON report
  Reporter-->>User: output report
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through parsers, ports, and tests,

Sniffed the types where looseness rests,
Warned the sandbox: do not update inside,
Rebuild hums and keeps your work aligned,
A tiny rabbit winks, then hops aside.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cli): add type-safety hotspot report' accurately summarizes the main change—a new developer command that analyzes and reports type-safety hotspots in the codebase.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/type-safety-hotspots

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

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
nemoclaw/src/commands/migration-state.ts (1)

262-276: ⚠️ Potential issue | 🟡 Minor

Pass env through external-root path resolution

detectHostOpenClaw accepts an env parameter, but on Line 430 collectExternalRoots(config, stateDir) still resolves paths with implicit process.env (via defaultWorkspacePath() and resolveUserPath() in registerRoot). This can produce inconsistent roots vs. workspaceDir when callers pass a non-default env.

💡 Proposed fix
-function collectExternalRoots(
-  config: OpenClawConfigDocument | null,
-  stateDir: string,
-): { roots: MigrationExternalRoot[]; warnings: string[]; errors: string[] } {
+function collectExternalRoots(
+  config: OpenClawConfigDocument | null,
+  stateDir: string,
+  env: NodeJS.ProcessEnv = process.env,
+): { roots: MigrationExternalRoot[]; warnings: string[]; errors: string[] } {
@@
-  const defaultsWorkspace = readTrimmedString(agentDefaults?.workspace);
-  const defaultWorkspace = defaultsWorkspace ?? defaultWorkspacePath();
+  const defaultsWorkspace = readTrimmedString(agentDefaults?.workspace);
+  const defaultWorkspace = defaultsWorkspace
+    ? resolveUserPath(defaultsWorkspace, env)
+    : defaultWorkspacePath(env);
@@
-          pathValue: workspace,
+          pathValue: resolveUserPath(workspace, env),
@@
-          pathValue: agentDir,
+          pathValue: resolveUserPath(agentDir, env),
@@
-        pathValue: extraDir,
+        pathValue: resolveUserPath(extraDir, env),
@@
-  const rootInfo = collectExternalRoots(config, stateDir);
+  const rootInfo = collectExternalRoots(config, stateDir, env);

Also applies to: 296-310, 328-329, 430-430

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

In `@nemoclaw/src/commands/migration-state.ts` around lines 262 - 276,
collectExternalRoots must accept and forward the environment object so path
resolution uses the same env as detectHostOpenClaw: add an env parameter to
collectExternalRoots and use it when calling defaultWorkspacePath (e.g.,
defaultWorkspacePath(env)) and when resolving user paths inside registerRoot
(replace resolveUserPath(...) with resolveUserPath(..., env) or otherwise pass
env through to that helper); update callers (including detectHostOpenClaw) to
pass their env through so workspace/default paths and any resolveUserPath uses
are consistent across the call chain (refer to functions collectExternalRoots,
registerRoot, defaultWorkspacePath, resolveUserPath, and detectHostOpenClaw).
src/lib/onboard-session.ts (1)

706-729: ⚠️ Potential issue | 🟠 Major

Re-sanitize failure before returning debug summaries.

endpointUrl is redacted on the way out, but failure is passed through verbatim. Because createSession() still accepts overrides.failure unchanged, summarizeForDebug() can leak raw bearer/API tokens when it is called with an in-memory session object instead of one that already went through normalizeSession().

🔐 Proposed fix
-    failure: session.failure,
+    failure: sanitizeFailure(session.failure),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard-session.ts` around lines 706 - 729, summarizeForDebug
currently redacts endpointUrl but returns session.failure verbatim, which can
leak tokens when called with an in-memory session; update summarizeForDebug to
re-sanitize the failure before returning (e.g., call the existing
normalizeSession or a dedicated redactFailure helper to strip/replace bearer/API
tokens and other secrets from session.failure) and return the sanitized failure
field instead of the raw session.failure; reference summarizeForDebug,
normalizeSession, redactUrl, and createSession to locate where to apply the
sanitization.
src/lib/platform.ts (1)

90-103: ⚠️ Potential issue | 🟡 Minor

Return empty candidates on unsupported platforms.

Line 102 currently returns Linux Podman socket paths for any non-darwin platform (including win32). Since getPodmanSocketCandidates is exported, direct callers can get invalid paths outside Linux/macOS.

Suggested fix
 function getPodmanSocketCandidates(opts: PlatformLookupOptions = {}): string[] {
   const home = opts.home ?? process.env.HOME ?? "/tmp";
   const platform = opts.platform ?? process.platform;
   const uid = opts.uid ?? process.getuid?.() ?? 1000;
 
   if (platform === "darwin") {
     return [
       path.join(home, ".local/share/containers/podman/machine/podman.sock"),
       "/var/run/docker.sock",
     ];
   }
 
-  return [`/run/user/${String(uid)}/podman/podman.sock`, "/run/podman/podman.sock"];
+  if (platform === "linux") {
+    return [`/run/user/${String(uid)}/podman/podman.sock`, "/run/podman/podman.sock"];
+  }
+
+  return [];
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/platform.ts` around lines 90 - 103, getPodmanSocketCandidates
currently returns Linux socket paths for any non-"darwin" platform, which yields
invalid candidates on unsupported platforms like "win32"; update
getPodmanSocketCandidates to explicitly handle platforms: return macOS paths
when opts.platform/process.platform === "darwin", return Linux paths when
platform === "linux" (using uid from opts.uid/process.getuid()), and return an
empty array for all other platforms so callers don't receive invalid socket
paths. Ensure references to opts.platform, process.platform, opts.uid,
process.getuid, and the uid variable remain correct when implementing the
branching.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/nemoclaw-user-reference/references/troubleshooting.md:
- Around line 359-364: Update step 3 in troubleshooting.md to recommend using
the existing automated command by replacing the manual backup/recreate
instruction with guidance to run the documented "nemoclaw <name> rebuild"
command (which performs backup, destroys the old sandbox, recreates it with the
current image, and restores state); ensure the text references the exact command
syntax "nemoclaw <name> rebuild" and optionally points readers to the earlier
section that documents that command (lines describing the rebuild behavior) for
consistency and safety.

In `@scripts/type-safety-hotspots.ts`:
- Around line 14-15: The current tsDirectiveCount uses countMatches(text,
COMMENT_DIRECTIVE_RE) which scans the whole file and picks up directives inside
strings; instead extract only comment text and run the regex against that: use
the TypeScript compiler API (e.g., ts.getLeadingCommentRanges and
ts.getTrailingCommentRanges on the SourceFile.getFullText()) or iterate over all
comment ranges via ts.forEachChild and collect comment ranges, concatenate their
substrings and call countMatches(commentsText, COMMENT_DIRECTIVE_RE) to compute
tsDirectiveCount; update any other uses (e.g., where `@ts-nocheck` was already
handled) to use the same comment-only extraction logic.
- Around line 392-504: The containsWeakType function is too large and should be
split into smaller per-node-kind helpers (e.g., handleParenthesizedType,
handleArrayType, handleTupleType, handleUnionIntersection, handleTypeLiteral,
handleTypeReference, handleFunctionOrConstructorType, handleConditionalType,
etc.) and a small dispatch table to call the correct handler for each
ts.TypeNode kind; each helper should accept (typeNode, aliases, seen) and return
boolean, preserve existing logic (including new Set(seen) where currently used),
and ensure containsWeakType becomes a thin dispatcher that delegates to these
helpers (or the map) to reduce cyclomatic complexity.

In `@src/lib/agent-defs.ts`:
- Around line 113-118: The code currently accepts any finite number for port
fields; update validation so ports are whole TCP port integers in the valid
range. In readNumberArray (and the equivalent single-number reader used for
health_probe.port) only accept entries where Number.isInteger(entry) is true and
entry >= 1 && entry <= 65535, filter out others and return undefined if no valid
ports remain; add the same integer+range check where health_probe.port is parsed
(referencing readNumberArray and the health probe parsing logic) so manifest
load fails fast on invalid ports.

---

Outside diff comments:
In `@nemoclaw/src/commands/migration-state.ts`:
- Around line 262-276: collectExternalRoots must accept and forward the
environment object so path resolution uses the same env as detectHostOpenClaw:
add an env parameter to collectExternalRoots and use it when calling
defaultWorkspacePath (e.g., defaultWorkspacePath(env)) and when resolving user
paths inside registerRoot (replace resolveUserPath(...) with
resolveUserPath(..., env) or otherwise pass env through to that helper); update
callers (including detectHostOpenClaw) to pass their env through so
workspace/default paths and any resolveUserPath uses are consistent across the
call chain (refer to functions collectExternalRoots, registerRoot,
defaultWorkspacePath, resolveUserPath, and detectHostOpenClaw).

In `@src/lib/onboard-session.ts`:
- Around line 706-729: summarizeForDebug currently redacts endpointUrl but
returns session.failure verbatim, which can leak tokens when called with an
in-memory session; update summarizeForDebug to re-sanitize the failure before
returning (e.g., call the existing normalizeSession or a dedicated redactFailure
helper to strip/replace bearer/API tokens and other secrets from
session.failure) and return the sanitized failure field instead of the raw
session.failure; reference summarizeForDebug, normalizeSession, redactUrl, and
createSession to locate where to apply the sanitization.

In `@src/lib/platform.ts`:
- Around line 90-103: getPodmanSocketCandidates currently returns Linux socket
paths for any non-"darwin" platform, which yields invalid candidates on
unsupported platforms like "win32"; update getPodmanSocketCandidates to
explicitly handle platforms: return macOS paths when
opts.platform/process.platform === "darwin", return Linux paths when platform
=== "linux" (using uid from opts.uid/process.getuid()), and return an empty
array for all other platforms so callers don't receive invalid socket paths.
Ensure references to opts.platform, process.platform, opts.uid, process.getuid,
and the uid variable remain correct when implementing the branching.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ff43f1e1-7646-470c-b522-6feb0b8ca6d7

📥 Commits

Reviewing files that changed from the base of the PR and between 2a29b5e and c518539.

📒 Files selected for processing (11)
  • .agents/skills/nemoclaw-user-reference/references/troubleshooting.md
  • nemoclaw/src/commands/migration-state.ts
  • package.json
  • scripts/type-safety-hotspots.ts
  • src/lib/agent-defs.test.ts
  • src/lib/agent-defs.ts
  • src/lib/onboard-session.ts
  • src/lib/platform.ts
  • src/lib/tiers.ts
  • test/policy-tiers.test.ts
  • test/type-safety-hotspots.test.ts

Comment thread scripts/type-safety-hotspots.ts
Comment thread scripts/type-safety-hotspots.ts
Comment thread src/lib/agent-defs.ts Outdated
Signed-off-by: Carlos Villela <cvillela@nvidia.com>

@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

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

Inline comments:
In `@scripts/type-safety-hotspots.ts`:
- Around line 883-884: The current scan only updates the file-level metric via
addPattern(fileMetrics, "tsDirectiveCount", countDirectiveComments(text)) and
never increments RawFunctionData.tsDirectiveCount, so inline TS suppressions
inside functions are missed by computeFunctionRawUnsafety() and
buildFunctionReasons(); modify the scanner that calls countDirectiveComments to
preserve each directive's position and, for each directive whose location falls
within the source range of the active functionStack entry, increment that
functionStack entry's RawFunctionData.tsDirectiveCount (and still increment the
fileMetrics counter), ensuring directive positions are captured and attributed
to the correct function.
- Around line 634-639: The matcher currently recognizes JSON.parse/JSON5.parse
and yaml.load (lowercase) plus YAML.parse (uppercase), but misses YAML.load
(uppercase); update the conditional that returns the parse boundary to also
match (owner.text === "YAML" && member === "load") and ideally consolidate the
YAML checks so both owner.text values ("YAML" and "yaml") accept both member
values ("parse" and "load")—modify the expression around the existing owner.text
=== "YAML"/"yaml" and member checks (the returned boolean expression) to include
these additional conditions or replace with a small set/array membership test to
cover both namespaces and both methods.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ebb76ddb-46ed-4c9e-875b-f17dc598cb3e

📥 Commits

Reviewing files that changed from the base of the PR and between c518539 and 99fb3a0.

📒 Files selected for processing (12)
  • .agents/skills/nemoclaw-user-reference/references/troubleshooting.md
  • docs/reference/troubleshooting.md
  • nemoclaw/src/commands/migration-state.test.ts
  • nemoclaw/src/commands/migration-state.ts
  • scripts/type-safety-hotspots.ts
  • src/lib/agent-defs.test.ts
  • src/lib/agent-defs.ts
  • src/lib/onboard-session.test.ts
  • src/lib/onboard-session.ts
  • src/lib/platform.ts
  • test/platform.test.ts
  • test/type-safety-hotspots.test.ts
✅ Files skipped from review due to trivial changes (4)
  • test/platform.test.ts
  • .agents/skills/nemoclaw-user-reference/references/troubleshooting.md
  • docs/reference/troubleshooting.md
  • src/lib/onboard-session.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/lib/agent-defs.ts
  • nemoclaw/src/commands/migration-state.ts
  • src/lib/agent-defs.test.ts
  • src/lib/platform.ts

Comment thread scripts/type-safety-hotspots.ts
Comment thread scripts/type-safety-hotspots.ts Outdated

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

Code reviewed: type-safety refactoring is clean, new hotspot tool has good test coverage, all CI green. LGTM.

@ericksoa ericksoa merged commit ed38d45 into main Apr 20, 2026
18 checks passed
@cv cv deleted the feat/type-safety-hotspots branch May 27, 2026 21:16
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output feature PR adds or expands user-visible functionality and removed NemoClaw CLI labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output feature PR adds or expands user-visible functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants