Skip to content

fix: address CodeRabbit review findings from v0.4.11 merge (#487) - #488

Open
humble-little-bear wants to merge 1 commit into
developfrom
agent/claude-bear/827dac50
Open

fix: address CodeRabbit review findings from v0.4.11 merge (#487)#488
humble-little-bear wants to merge 1 commit into
developfrom
agent/claude-bear/827dac50

Conversation

@humble-little-bear

Copy link
Copy Markdown
Collaborator

Fixes all 8 actionable CodeRabbit review comments from #487 (the v0.4.11 develop→master merge).

Changes

Logging (offckb logs)

  • logs script scanned only the last tail lines before filtering, so sparse ckb-script entries were usually missed → scan a 100× wider window, trim to tail after filtering (src/cmd/logs.ts)
  • Unknown log targets (e.g. offckb logs scrpit) silently fell back to the node log → now rejected with the accepted values (src/cmd/logs.ts)
  • followLogFile detected rotation only as a size decrease; a rotated-in file already larger than the old one was read from a stale offset → reset on inode change too, with the test now modeling real rotation (rename + larger replacement) (src/devnet/log-file.ts, tests/logs.test.ts)

Chain init

  • semver.gte('0.205.0-rc1', '0.205.0') is false, so 0.205.0 rc binaries had the Terminal RPC module stripped → use semver.satisfies(v, '>=0.205.0-0') (src/node/init-chain.ts)

ckb-tui install

  • A binary that lost its execute bit passed verification and failed later at spawn time → X_OK check on POSIX routes it into the reinstall path (src/tools/ckb-tui.ts)

RPC proxy

  • A failed proxy.log rollover (e.g. locked file on Windows) set size = -1 and dropped every later event → rollover failure now keeps appending and retries on the next event (src/tools/proxy-events.ts)
  • Batched JSON-RPC requests were never recorded (batched send_transaction txs lost), and missing/non-array params threw a TypeError misreported as a parse error → normalize payloads to an array, guard params (src/tools/proxy-events.ts)
  • ctx annotated as ProxyEventContext; --verbose now wires a debug-level sink so per-request "RPC Req" lines print during verbose runs (src/tools/rpc-proxy.ts, src/cmd/node.ts)

Tests

  • New/updated coverage: sparse-script tail scan, unknown-target rejection, inode rotation, 0.205.0 rc gating, execute-bit mismatch, rollover-failure append + retry, batch request handling, params guard
  • Full suite: 36 suites, 316 passed / 7 skipped (pre-existing), 0 failed; tsc --noEmit clean; build passes

🤖 Generated with Claude Code

- logs: scan a wider window before script-filtering the tail so sparse
  ckb-script entries are not missed; reject unknown log targets instead
  of silently falling back to node
- log-file: detect rotation by inode change in followLogFile, not only
  by size decrease; test rotation via rename + larger replacement file
- init-chain: accept CKB 0.205.0 prereleases for Terminal RPC gating via
  semver range '>=0.205.0-0'
- ckb-tui: treat a binary without the execute bit as a mismatch so it
  flows into the reinstall path (POSIX only)
- proxy-events: keep appending events when a proxy.log rollover fails
  and retry on the next event; normalize batch JSON-RPC request payloads
  and guard non-array send_transaction params
- rpc-proxy: annotate ctx as ProxyEventContext and wire --verbose to a
  debug-level sink so per-request lines print during verbose runs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved log tailing for sparse script logs and file rotation.
    • Invalid log targets now produce clear errors.
    • Fixed detection of CKB prerelease Terminal RPC support.
    • Prevented non-executable ckb-tui binaries from being accepted.
    • Improved proxy log rollover reliability.
    • Added support for batched RPC requests and clearer send_transaction warnings.
  • Enhancements

    • Verbose mode now includes detailed proxy request logging.

Walkthrough

The patch fixes sparse script-log scanning, invalid log-target handling, inode-based log rotation, CKB prerelease detection, non-executable binary validation, RPC proxy batching and warnings, rollover retries, and verbose proxy logging.

Changes

CLI fixes

Layer / File(s) Summary
Log scanning and rotation
src/cmd/logs.ts, src/devnet/log-file.ts, tests/logs-command.test.ts, tests/logs.test.ts
Script logs scan beyond the raw tail window before filtering. Invalid explicit targets now throw errors. File following resets state after inode changes. Tests cover sparse entries, invalid targets, truncation, and rotation.
RPC proxy requests and logging
src/tools/rpc-proxy.ts, src/tools/proxy-events.ts, src/cmd/node.ts, tests/proxy-events.test.ts
The proxy accepts verbose configuration, handles batch requests, validates send_transaction parameters, and retries failed rollover operations.
Version and binary compatibility
src/node/init-chain.ts, src/tools/ckb-tui.ts, tests/init-chain.test.ts, tests/ckb-tui-install.test.ts, .changeset/review-fixes-v0411.md
Terminal RPC detection accepts 0.205.0 prereleases. Non-Windows binaries must be executable. Tests and the patch changeset record these fixes.

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

Sequence Diagram(s)

sequenceDiagram
  participant nodeDevnet
  participant RPCProxy
  participant handleOneRequest
  participant UnifiedLogger
  nodeDevnet->>RPCProxy: createRPCProxy(..., { verbose })
  RPCProxy->>UnifiedLogger: select debug sink when verbose
  RPCProxy->>handleOneRequest: process each batch payload
  handleOneRequest->>UnifiedLogger: log request and validation warning
Loading

Possibly related PRs

Suggested reviewers: retricsu

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the pull request as fixes for review findings from the v0.4.11 merge.
Description check ✅ Passed The description directly explains the eight fixes, affected components, tests, and validation results.
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.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/cmd/logs.ts`:
- Around line 37-39: Validate the parsed tail value before calculating
scanWindow in the logs command, rejecting zero (including -0) and any
non-positive value so script mode never reaches slice(-tail) with zero. Keep the
existing positive-tail behavior unchanged.

In `@src/node/init-chain.ts`:
- Around line 76-78: Update supportsTerminalRpcModule so newer Terminal RPC
prereleases, including versions with greater patch or minor values than
TERMINAL_RPC_MIN_CKB_VERSION, satisfy the minimum-version check. Adjust the
semver comparison to include prereleases across newer versions while preserving
the existing true behavior for null or invalid versions.

In `@src/tools/proxy-events.ts`:
- Around line 66-74: Update the rollover logic around the fs.rmSync and
fs.renameSync calls to preserve the existing `${filePath}.1` archive: move it to
a temporary path, attempt the active-log rename, and restore the archive when
that rename fails before retaining append behavior. Add a test covering
renameSync failing after the archive is successfully moved or removed, and
verify the prior archive remains intact.
- Around line 99-100: Update the batch iteration in the proxy event handling
flow around handleOneRequest to validate each member is a non-null object before
dispatching it, skip invalid members, and continue processing subsequent
requests. Add a batch test covering an invalid member before a valid
send_transaction request and verify the valid transaction is still recorded.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5021b574-85d7-4da2-934b-4666f77366e7

📥 Commits

Reviewing files that changed from the base of the PR and between 51f437e and c759b19.

📒 Files selected for processing (13)
  • .changeset/review-fixes-v0411.md
  • src/cmd/logs.ts
  • src/cmd/node.ts
  • src/devnet/log-file.ts
  • src/node/init-chain.ts
  • src/tools/ckb-tui.ts
  • src/tools/proxy-events.ts
  • src/tools/rpc-proxy.ts
  • tests/ckb-tui-install.test.ts
  • tests/init-chain.test.ts
  • tests/logs-command.test.ts
  • tests/logs.test.ts
  • tests/proxy-events.test.ts

Comment thread src/cmd/logs.ts
Comment on lines +37 to +39
const scanWindow = scriptOnly ? tail * SCRIPT_SCAN_FACTOR : tail;
let lines = readLogTail(filePath, scanWindow);
if (scriptOnly) lines = filterLinesByTarget(lines, SCRIPT_LOG_TARGET).slice(-tail);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 4 --glob '*.ts' 'LogsOptions|--tail|tail\s*=' src tests

Repository: ckb-devrel/offckb

Length of output: 4243


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- src/cli.ts option parser ---\n'
sed -n '108,119p' src/cli.ts | cat -n

printf '\n--- src/cmd/logs.ts implementation ---\n'
sed -n '1,70p' src/cmd/logs.ts | cat -n

printf '\n--- tests for zero/negative tail ---\n'
rg -n -C 5 --glob '*.ts' 'tail:\s*0|0x|negative|InvalidArgumentError|--tail' tests src/cli.ts || true

printf '\n--- read-only JS slice behavioral probe ---\n'
node - <<'JS'
const arr = [1,2,3,4,5];
for (const n of [0, 1, -1, -0, Number('-0'), NaN, undefined]) {
  try {
    console.log(`${JSON.stringify(n)} => ${JSON.stringify(arr.slice(n))} (idx=${arr.slice(n).indexOf(4)})`);
  } catch (e) {
    console.log(`${JSON.stringify(n)} => throws ${e.name}: ${e.message}`);
  }
}
JS

Repository: ckb-devrel/offckb

Length of output: 246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- src/cli.ts option parser ---'
sed -n '108,119p' src/cli.ts | cat -n

printf '%s\n' ''
printf '%s\n' '--- src/cmd/logs.ts implementation ---'
sed -n '1,70p' src/cmd/logs.ts | cat -n

printf '%s\n' ''
printf '%s\n' '--- tests for zero/negative tail ---'
rg -n -C 5 --glob '*.ts' 'tail:\s*0|negative|InvalidArgumentError|--tail' tests src/cli.ts || true

printf '%s\n' ''
printf '%s\n' '--- read-only JS slice behavioral probe ---'
node - <<'JS'
const arr = [1,2,3,4,5];
for (const n of [0, 1, -1, -0, Number('-0'), NaN, undefined]) {
  try {
    console.log(`${JSON.stringify(n)} => ${JSON.stringify(arr.slice(n))}`);
  } catch (e) {
    console.log(`${JSON.stringify(n)} => throws ${e.name}: ${e.message}`);
  }
}
JS

Repository: ckb-devrel/offckb

Length of output: 7810


Reject --tail 0 or enforce a minimum before slicing.

--tail accepts 0, and --tail -0 also passes through as 0. In script mode, lines.slice(-0) becomes lines.slice(0), so the command returns all filtered lines instead of omitting output. Reject zero before calculating scanWindow, or require tail > 0.

🤖 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/cmd/logs.ts` around lines 37 - 39, Validate the parsed tail value before
calculating scanWindow in the logs command, rejecting zero (including -0) and
any non-positive value so script mode never reaches slice(-tail) with zero. Keep
the existing positive-tail behavior unchanged.

Comment thread src/node/init-chain.ts
Comment on lines 76 to +78
export function supportsTerminalRpcModule(ckbVersion: string | null | undefined): boolean {
if (ckbVersion == null || !semver.valid(ckbVersion)) return true;
return semver.gte(ckbVersion, TERMINAL_RPC_MIN_CKB_VERSION);
return semver.satisfies(ckbVersion, `>=${TERMINAL_RPC_MIN_CKB_VERSION}-0`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

node <<'NODE'
const semver = require('semver');
const range = '>=0.205.0-0';

for (const version of ['0.205.0-rc1', '0.205.1-rc1', '0.206.0-rc1']) {
  console.log(version, semver.satisfies(version, range));
}
NODE

Repository: ckb-devrel/offckb

Length of output: 208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Tracked init-chain/node files:\n'
git ls-files | rg '(^|/)init-chain\.ts$|(^|/)node\.ts$|(^|/)package\.json$' || true

printf '\nRelevant init-chain snippet:\n'
if [ -f src/node/init-chain.ts ]; then
  nl -ba src/node/init-chain.ts | sed -n '1,130p'
fi

printf '\nRelevant node.ts uses:\n'
if [ -f src/node/node.ts ]; then
  rg -n "supportsTerminalRpcModule|Terminal|devnet|includePrerelease|semver\.satisfies" src/node/node.ts -C 4
fi

printf '\nPackage semver declarations:\n'
node - <<'JS'
const fs = require('fs');
for (const p of ['package.json']) {
  if (fs.existsSync(p)) {
    const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
    console.log(p, 'dependencies.semver=', pkg.dependencies?.semver);
    console.log(p, 'devDependencies.semver=', pkg.devDependencies?.semver);
  }
}
JS

printf '\nLocal semver version and comparison behavior:\n'
node - <<'JS'
const semver = require('semver');
const range = '>=0.205.0-0';
for (const version of ['0.205.0-rc1', '0.205.1-rc1', '0.205.1', '0.206.0-rc1', '0.206.0']) {
  console.log(version, semver.satisfies(version, range), semver.satisfies(version, range, { includePrerelease: true }), semver.gte(version, '0.205.0'));
}
JS

Repository: ckb-devrel/offckb

Length of output: 308


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo 'Relevant init-chain snippet:'
awk '{ printf "%6d\t%s\n", NR, $0 }' src/node/init-chain.ts | sed -n '1,130p'

echo
echo 'Relevant cmd/node.ts matches:'
grep -n -C 5 "supportsTerminalRpcModule\|Terminal\|devnet\|includePrerelease\|semver\.satisfies" src/cmd/node.ts || true

echo
echo 'Package semver declarations:'
node - <<'JS'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log('dependencies.semver=', pkg.dependencies?.semver);
console.log('devDependencies.semver=', pkg.devDependencies?.semver);
JS

echo
echo 'Local semver version and comparison behavior:'
node - <<'JS'
const semver = require('semver');
const range = '>=0.205.0-0';
console.log('semver version=', require('semver/gte').version);
for (const version of ['0.205.0-rc1', '0.205.1-rc1', '0.205.1', '0.206.0-rc1', '0.206.0']) {
  console.log(version, 'satisfies default=', semver.satisfies(version, range), 'satisfies prerelease=', semver.satisfies(version, range, { includePrerelease: true }), 'gte min=', semver.gte(version, '0.205.0'));
}
JS

Repository: ckb-devrel/offckb

Length of output: 24141


🌐 Web query:

semver package npm compare prereleases includePrerelease >=X prerelease same major minor patch

💡 Result:

In the npm semver package, the includePrerelease option fundamentally alters how range-matching functions behave regarding prerelease versions, but it does not affect direct comparison functions [1][2]. 1. Range Matching and includePrerelease By default, the semver package excludes prerelease versions from satisfying ranges to prevent unstable versions from being accidentally selected [2][3]. For example, a range like >1.2.3-alpha.3 will not be satisfied by 3.4.5-alpha.9 even though it is technically greater [2][3]. When the includePrerelease: true option is passed to range-matching functions (such as satisfies, maxSatisfying, or minVersion), it treats prerelease versions as if they were standard release versions, allowing them to satisfy the range [2][4]. 2. Important Constraint for Ranges Even when includePrerelease is not used, a prerelease version can only satisfy a range if at least one comparator in the range contains the same [major, minor, patch] tuple and also includes a prerelease tag [2][3]. This prevents a prerelease version from accidentally matching a range that was intended only for stable releases [2][3]. 3. Comparison Functions Comparison functions (such as compare, lt, gt, eq, compareLoose) do not use the includePrerelease option [1]. These functions always compare the prerelease parts of a version if the [major, minor, patch] components are identical [1]. Consequently, they do not require or respect this flag [1]. Summary of Behavior - For range functions (e.g., semver.satisfies(v, r, { includePrerelease: true })): Prerelease tags are treated as normal parts of the version, enabling them to satisfy ranges that would otherwise exclude them [2]. - For direct comparison functions (e.g., semver.lt(v1, v2)): The includePrerelease option has no effect [1]. These functions consistently evaluate version precedence according to SemVer rules, including prerelease identifiers [1][2].

Citations:


Allow newer Terminal RPC prereleases to pass the minimum-version check.

With >=0.205.0-0, prereleases are rejected unless they use the same [major, minor, patch] tuple as the comparator. Versions such as 0.205.1-rc1 or 0.206.0-rc1 are newer than 0.205.0, but supportsTerminalRpcModule() returns false; node startup then throws before launching CKB when the config enables Terminal.

Proposed fix
-  return semver.satisfies(ckbVersion, `>=${TERMINAL_RPC_MIN_CKB_VERSION}-0`);
+  return semver.satisfies(ckbVersion, `>=${TERMINAL_RPC_MIN_CKB_VERSION}-0`, {
+    includePrerelease: true,
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function supportsTerminalRpcModule(ckbVersion: string | null | undefined): boolean {
if (ckbVersion == null || !semver.valid(ckbVersion)) return true;
return semver.gte(ckbVersion, TERMINAL_RPC_MIN_CKB_VERSION);
return semver.satisfies(ckbVersion, `>=${TERMINAL_RPC_MIN_CKB_VERSION}-0`);
export function supportsTerminalRpcModule(ckbVersion: string | null | undefined): boolean {
if (ckbVersion == null || !semver.valid(ckbVersion)) return true;
return semver.satisfies(ckbVersion, `>=${TERMINAL_RPC_MIN_CKB_VERSION}-0`, {
includePrerelease: true,
});
🤖 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/node/init-chain.ts` around lines 76 - 78, Update
supportsTerminalRpcModule so newer Terminal RPC prereleases, including versions
with greater patch or minor values than TERMINAL_RPC_MIN_CKB_VERSION, satisfy
the minimum-version check. Adjust the semver comparison to include prereleases
across newer versions while preserving the existing true behavior for null or
invalid versions.

Comment thread src/tools/proxy-events.ts
Comment on lines +66 to +74
try {
fs.rmSync(`${filePath}.1`, { force: true });
fs.renameSync(filePath, `${filePath}.1`);
size = 0;
} catch {
// Rollover failed (for example the file is locked). Keep
// appending so events are not lost, and retry on the next event.
size = maxBytes;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve the prior rotated log when the active-log rename fails.

Line 67 deletes proxy.log.1 before Line 68 proves that the active log can replace it. If renameSync(filePath, \${filePath}.1`)` fails after deletion, the catch block keeps new events but permanently loses the prior archive.

Move the existing archive to a temporary path and restore it if the active-log rename fails. Add a test that makes renameSync fail after successful archive removal.

🤖 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/tools/proxy-events.ts` around lines 66 - 74, Update the rollover logic
around the fs.rmSync and fs.renameSync calls to preserve the existing
`${filePath}.1` archive: move it to a temporary path, attempt the active-log
rename, and restore the archive when that rename fails before retaining append
behavior. Add a test covering renameSync failing after the archive is
successfully moved or removed, and verify the prior archive remains intact.

Comment thread src/tools/proxy-events.ts
Comment on lines +99 to +100
for (const jsonRpcContent of Array.isArray(parsed) ? parsed : [parsed]) {
handleOneRequest(jsonRpcContent, ctx);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Skip malformed batch members without stopping the batch.

JSON.parse accepts null. For [null, { "method": "send_transaction", "params": [tx] }], handleOneRequest dereferences .method on null. The outer catch then exits the loop, so the valid transaction is not recorded.

Validate that each batch member is a non-null object before calling handleOneRequest. Continue after invalid members. Add a batch test with an invalid member before a valid send_transaction request.

🤖 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/tools/proxy-events.ts` around lines 99 - 100, Update the batch iteration
in the proxy event handling flow around handleOneRequest to validate each member
is a non-null object before dispatching it, skip invalid members, and continue
processing subsequent requests. Add a batch test covering an invalid member
before a valid send_transaction request and verify the valid transaction is
still recorded.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant