Skip to content

fix(test): resolve Biome noUnsafeOptionalChaining lint errors (#1341)#1343

Closed
github-actions[bot] wants to merge 21 commits into
perf/full-path-benchmark-optimizationfrom
claude-fix-pr-1341-29559960186
Closed

fix(test): resolve Biome noUnsafeOptionalChaining lint errors (#1341)#1343
github-actions[bot] wants to merge 21 commits into
perf/full-path-benchmark-optimizationfrom
claude-fix-pr-1341-29559960186

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

CI Auto-Fix

Original PR: #1341
Failed CI Run: Non-Main Branch CI/CD
Failed Job: dev-build-deploy (bun run lint step)

Root Cause

bun run lint exited 1 with 2 errors (lint/correctness/noUnsafeOptionalChaining) in tests/unit/instrumentation-crash-handler.test.ts. The Biome spec floats (@biomejs/biome: ^2, no lockfile) and resolved to 2.5.4, whose noUnsafeOptionalChaining rule flags process.report?.writeReport because the optional-chained result flows into an unconditional .mock access (would throw TypeError if process.report were undefined). The 196 useOptionalChain findings are warnings and do not fail the build.

Fix Applied

File Line Change Type
tests/unit/instrumentation-crash-handler.test.ts 134, 149 process.report?.writeReport -> process.report!.writeReport lint correctness

process.report is guaranteed present here: writeReport is only spied when process.report exists (beforeEach), and excludeEnv is asserted on the preceding line. noNonNullAssertion is off in biome.json, so the non-null assertion is permitted. Runtime behavior is unchanged.

Verification

  • bun run typecheck passes (exit 0)
  • bun run lint passes (exit 0, 2 errors resolved; only pre-existing warnings/infos remain)
  • vitest run tests/unit/instrumentation-crash-handler.test.ts -> 9/9 tests pass
  • No logic changes; only ?. -> ! on a guaranteed-present object

Auto-generated by Claude AI

Greptile Summary

This PR introduces a single commit on top of the perf/full-path-benchmark-optimization branch that fixes two Biome 2.5.4 lint/correctness/noUnsafeOptionalChaining errors in the crash-handler test suite. The 129 files listed in the PR diff belong to the underlying branch, not this fix commit.

  • Changed lines (2): process.report?.writeReportprocess.report!.writeReport in the two "genuine errors" test cases; the optional-chain form was flagged because .mock is accessed unconditionally on the chain result, which would throw TypeError if process.report were undefined.
  • Correctness of the fix: In the first test, expect(process.report?.excludeEnv).toBe(true) on the preceding line already acts as an implicit non-null guard. In the second test, the beforeEach spy setup only runs when process.report exists, and Node.js always surfaces process.report. The noNonNullAssertion rule is confirmed \"off\" in biome.json.

Confidence Score: 5/5

The change is a two-line test-only substitution that replaces optional-chain syntax with non-null assertions; it introduces no logic changes and restores CI green.

The only touched file is a test file, and both non-null assertion sites are correctly backed — the first by an explicit toBe(true) guard on the preceding line, the second by the beforeEach spy condition that only runs when process.report exists. The noNonNullAssertion rule is confirmed disabled in biome.json. No source files are modified.

No files require special attention; tests/unit/instrumentation-crash-handler.test.ts is the only changed file in the fix commit and the substitution is mechanically correct.

Important Files Changed

Filename Overview
tests/unit/instrumentation-crash-handler.test.ts Two ?.!. replacements on process.report.writeReport to resolve Biome noUnsafeOptionalChaining; both sites are correctly guarded (by assertion or beforeEach spy condition), and noNonNullAssertion is off in biome.json.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Test
    participant beforeEach
    participant processReport as process.report (Node built-in)
    participant uncaughtException as crash handler

    beforeEach->>processReport: if process.report exists → vi.spyOn writeReport
    processReport-->>beforeEach: spy installed

    Test->>uncaughtException: uncaughtException(error)
    uncaughtException->>processReport: "report.excludeEnv = true"
    uncaughtException->>processReport: report.writeReport(filename, toSafeCrashError(error))
    processReport-->>uncaughtException: empty string (mocked)

    Test->>processReport: expect(process.report?.excludeEnv).toBe(true) — implicit guard
    Test->>processReport: process.report!.writeReport — non-null assertion safe
    Test->>Test: assert reportCalls[0][1] matches expected error
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Test
    participant beforeEach
    participant processReport as process.report (Node built-in)
    participant uncaughtException as crash handler

    beforeEach->>processReport: if process.report exists → vi.spyOn writeReport
    processReport-->>beforeEach: spy installed

    Test->>uncaughtException: uncaughtException(error)
    uncaughtException->>processReport: "report.excludeEnv = true"
    uncaughtException->>processReport: report.writeReport(filename, toSafeCrashError(error))
    processReport-->>uncaughtException: empty string (mocked)

    Test->>processReport: expect(process.report?.excludeEnv).toBe(true) — implicit guard
    Test->>processReport: process.report!.writeReport — non-null assertion safe
    Test->>Test: assert reportCalls[0][1] matches expected error
Loading

Reviews (1): Last reviewed commit: "fix(test): resolve unsafe optional chain..." | Re-trigger Greptile

ding113 and others added 21 commits July 14, 2026 19:24
…ssion control

Replace the single postgres.js pool with three isolated lanes (data,
control, writer) that share a configurable total connection budget.
Each lane gets a per-pool outstanding-operation admission wrapper
that fast-fails with DB_POOL_ADMISSION_EXCEEDED before saturating the
underlying driver queue, preventing unbounded memory growth under
load.

Route handlers now wrap with withDataDbScope so request-path queries
use the data lane via AsyncLocalStorage, while control-plane and
writer traffic remain isolated. Add statement_timeout and
lock_timeout at the connection level so slow SQL cannot block the
streaming finalization deadline.

Introduce LOCAL_OVERLOAD error category so admission rejections are
never retried, failovered, or counted against Provider/endpoint
circuits.
Introduce createDemandDrivenResponsePump to replace the TransformStream
+ tee() pipeline with a single high-water-mark-0 ReadableStream that
primes exactly one upstream chunk and never reads ahead past
unconsumed downstream demand. This eliminates unbounded buffering for
slow clients and removes the generic streaming stale watchdog.

Rewrite nodeStreamToWebStreamSafe to pause/resume the Node source on
controller.desiredSize backpressure, handle pre-existing
errored/destroyed/closed states before listener registration, and guard
delayed asynchronous destroy(error) events so they cannot surface as
uncaught exceptions after the Web stream has settled.

Defer all circuit-breaker, session-binding, and Codex cache side
effects into post-terminal tasks so a slow Redis call cannot turn an
already-completed billable request into a fallback 500 or block lease
settlement.
…ssage requests

Introduce enqueueMessageRequestUpdateDurably which returns a Promise
that resolves only after the batch SQL commits, using RETURNING id and
a status_code IS NULL fence to guarantee exactly-once terminal
persistence. If the durable write fails or the row is already
finalized, a conditional fallback (updateMessageRequestDetailsIfUnfinalized)
prevents overwriting an existing terminal status.

The write buffer now uses a dedicated writer-lane DB handle, an
evictable min-heap for priority-aware overflow dropping, and aggregated
overflow logging. Public-status rollup callbacks fire only after the
batch commit acknowledgement, preventing premature or duplicate
rollup emission when a timeout fallback races with a late primary
write.
… leases atomically

Consolidate all rolling-window and fixed-window cost writes into one
Redis pipeline per trackCost / trackUserDailyCost call, eliminating
sequential round-trips. The unified TRACK_COST_ROLLING_WINDOW script
is now write-only (cleanup + append + TTL repair) and no longer scans
the full ZSET on every successful request.

Add settleLeaseBudgets: a single Lua invocation that validates all
twelve lease keys, applies decrements, and writes an idempotency
marker in one atomic step. Replace twelve fire-and-forget
decrementLeaseBudget calls with one settlement, preventing duplicate
deductions on ioredis reconnect.

Configure commandTimeout, socketTimeout, and autoResendUnfulfilledCommands
on the shared Redis client so a TCP blackhole cannot grow the command
queue or replay timed-out writes after reconnection.
…uiescence

AsyncTaskManager.register now accepts a factory invoked after
admission rather than a pre-started Promise, enabling shutdown to
abort and join all pending generations—including tail tasks
registered by abort listeners. shutdownAll returns a shared Promise
that loops until the pending set is empty.

runApplicationCleanup treats async-task settlement, writer flush, and
DB pool close as non-detachable critical barriers: per-step timeouts
become soft warnings, and failures propagate to server.js which exits
non-zero. The hard-exit watchdog timer is now referenced so the
process stays alive long enough to report a truthful exit status.
Replace the raw headersToRecord helper with redactHeaders so
authorization, cookie, x-api-key, and set-cookie values are masked
before being written to Langfuse generation metadata, preventing
secret leakage in observability exports.
Verify that buildRedisOptionsForUrl sets commandTimeout, socketTimeout,
and autoResendUnfulfilledCommands on both redis:// and rediss:// URLs,
and that REDIS_COMMAND_TIMEOUT_MS overrides the defaults. Guards the
rate-limit performance commit against silent regressions in Redis
client hardening.
…callback

The public-status rollup test for timed-out durable waiters previously
typed onCommitted as () => void and invoked it with no arguments,
mismatching the real DurableMessageRequestUpdateOptions contract which
receives the committed MessageRequestUpdatePatch. Align the test mock
and invocation so the delayed-commit path exercises the actual callback
signature. Also fix import ordering in message.ts to satisfy the
formatter.
Replace fire-and-forget safeSend with a per-WebSocket outbound queue
that caps pending bytes at 1 MiB, serializes sends behind a single
in-flight callback, and pauses the upstream SSE response until the
client drains. Late callbacks from a closed socket are invalidated by
generation counter so they cannot deliver stale frames.

Guard the internal HTTP request body write with a 30 s drain timeout
and destroy both the request and response when the client vanishes
mid-payload. Error and close paths now send a structured error frame
before initiating the WebSocket close handshake so clients always
receive a terminal event.
Capture the sessionId at increment time into a dedicated variable so
the finally block decrements exactly the session it acquired, even if
ProxySession.fromContext or the guard pipeline mutates session state
before forwarding begins. Previously the finally block re-read
session.sessionId, which could be null or different by the time the
handler reached its cleanup path, leaking a concurrency slot.

Add unit tests covering early guard rejection, successful forwarding,
post-session error translation, and pre-session decode failures.
Replace the cloned-response reader pattern with a single
demand-driven response pump that feeds the client stream and observes
chunks for stats collection. The client now receives a new Response
wrapping the pump stream instead of the original upstream Response,
eliminating the unbounded clone that held a second copy of every
streaming byte in memory.

The pump arms a 60 s deadline on each unconsumed lookahead chunk so a
connected-but-non-reading client cannot pin the upstream connection
indefinitely. Client cancellation propagates to the source even when
the cancel observer throws, and reentrant cancel calls preserve the
first hard-cancel owner.

Response handler terminal paths now use durable persistence with
conditional fallback and bounded failure deadlines so a hanging
database cannot stall the streaming task indefinitely.
…king

Switch error-handler from separate duration and details writes to a
single updateMessageRequestDetailsDurably call that includes
durationMs, ensuring the Langfuse trace, persistence commit, and
status-tracker endRequest fire in deterministic order. The trace is
emitted first, the durable write is awaited, and only then is the
status tracker released — so a database failure surfaces as a
rejected handler rather than a silently orphaned trace.

Add comprehensive unit tests for client-safe message sanitisation,
override application, terminal status mapping, durable persistence
ordering, and the end-to-end terminal outcome contract.
…ansport controller

Replace combineAbortSignals polyfill with a dedicated
AbortController whose abort is driven by lightweight
bindClientAbortListener registrations on the response and client
signals. The client-signal listener is cleaned up as soon as the
forwarder obtains the upstream response, so a client disconnect after
headers no longer aborts the in-flight transport — only the response
controller retains that authority through stream consumption.

Add an integration test exercising real loopback transports through
the hedge lifecycle: winner settlement fences loser timers, each
launched transport releases its agent exactly once, database overload
is classified before fanout, and hedge winner/loser billing fires
exactly once per request.
Add a PostgreSQL integration test that exercises the async message
write buffer under row-level locks: mixed durable/ordinary batches
settle only after commit, timed-out primaries yield to fallback
ownership, retired pending patches are excluded from reinserted
generations, a saturated 5000-entry queue evicts non-terminal patches
while retaining terminal priority, and winner-cost retries respect
the bounded cadence with authoritative loser-cost accumulation.
Align test assertions with the production call site, which now
requires a timezone argument to resolve date presets deterministically.
…, and readback

Add a shared drizzle query tracing harness and comprehensive unit
tests for the message repository: terminal detail writes with
durable acknowledgement and CAS-guarded unfinalized claims, winner
and hedge-loser cost accounting with idempotent retries, session
stats aggregation with provider/model/cache-TTL grouping, paged
session request queries with adjacent-sequence lookup, usage-log
filtering with ledger fallback, and public readback projections for
single-request, session, and audit lookups.
Diagnostic reports now exclude the entire process environment via
--report-exclude-env in both Dockerfiles. Crash handlers wrap database
errors through findSafeDatabaseError before writing report files or
stderr fallbacks, preventing DrizzleQueryError SQL text and bound
parameters from reaching any public boundary.

The proxy error handler returns a generic 503/500 for database failures
without loading system settings or awaiting durable persistence.
Langfuse traces and session metadata strip x-cch-* reserved internal
headers. clearSessionProvider uses a Redis CAS compare so late cleanup
from a prior provider cannot delete a binding already moved to a new
one.
The first durable write claimant owns the terminal patch; later
contenders observe its acknowledgement but cannot overwrite the
committed outcome. Request duration is merged into the same CAS patch
so overflow or process exit cannot leave a permanently active record.

Post-terminal side effects (provider circuit mutation, session binding
clear, Codex cache binding) fire from an onCommitted callback after
the SQL write is acknowledged rather than speculatively before it.

server.js WebSocket turns track per-turn request, response, and settle
lifecycle: sendErrorAndClose aborts the active internal request before
queuing a fatal frame, and terminal events wait for their WS send
acknowledgement before releasing turn ownership.
Background schedulers (probe, public-status, log-cleanup) now expose
their in-flight promise so shutdown awaits true quiescence instead of
racing a fixed timeout. Bull queues are joined before DB pool and
Redis closure; failures are collected into an AggregateError so
critical cleanup still runs.

Ledger backfill registers as a cancellable AsyncTaskManager job with
abort-signal checkpoints between batches. The lease settlement Lua
script consumes the cached slice when a request exceeds the remaining
budget, preventing repeated overshoot within the refresh window.
Biome 2.5.4 emits lint/correctness/noUnsafeOptionalChaining on the two
process.report?.writeReport accesses in the crash-handler test because
the optional-chained result flows into an unconditional .mock property
access (would throw TypeError if process.report were undefined).

process.report is guaranteed present in these cases: writeReport is only
spied when process.report exists (beforeEach), and excludeEnv is asserted
on the line above. Switch to a non-null assertion (noNonNullAssertion is
off in biome.json). Behavior unchanged; restores `bun run lint` to exit 0.

CI Run: https://github.com/ding113/claude-code-hub/actions/runs/29559924912

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d9f63954c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

let errorCategory = await categorizeErrorAsync(error);
lastErrorCategory = errorCategory;
const statusCode = error instanceof ProxyError ? error.statusCode : undefined;
const databaseError = findSafeDatabaseError(error);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle local DB errors before retrying hedge providers

In hedge mode, when a Drizzle query error that is not a pool-admission error is thrown while an attempt is being prepared or handled, databaseError is non-null but errorCategory remains SYSTEM_ERROR because categorizeErrorAsync only maps admission errors. The code then records an endpoint failure and falls through to provider failure/alternative launch logic, even though switching providers cannot fix a local DB outage and can poison endpoint health. Mirror the non-hedge path by overriding the category or branching on any databaseError before endpoint accounting.

Useful? React with 👍 / 👎.

@ding113 ding113 closed this Jul 22, 2026
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant