Skip to content

release: v0.4.0#259

Merged
fyZhang66 merged 1 commit into
mainfrom
release/v0.4.0
Jul 17, 2026
Merged

release: v0.4.0#259
fyZhang66 merged 1 commit into
mainfrom
release/v0.4.0

Conversation

@fyZhang66

@fyZhang66 fyZhang66 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

TestSprite CLI v0.4.0. Full details in CHANGELOG.md.

Added

  • test cancel <run-id...> — cancel in-flight runs (Ctrl-C now detaches gracefully during --wait; cancel is the explicit stop)
  • project delete <project-id> --confirm — cascade-delete a project and everything under it
  • Backend stdout + Python traceback surfaced in test result and failure bundles
  • Backend dependency declarations are now readable (test get) and editable (test update --produces/--needs/--category)
  • Version-compatibility handshake — upgrade advisory when the CLI is below the backend's supported floor; HTTP 426 maps to exit 14
  • auth status / doctor show the account's platform routing when reported by the backend

Changed / Fixed

  • Graceful SIGINT/SIGTERM detach during --wait (exit 130/143/129, partial JSON envelope, re-attach hint)
  • project create --description now fails fast with a clear error (projects have no description field)
  • Backend run cards render steps: n/a (backend) instead of a misleading 0/0
  • The testsprite-verify skill routes local-only changes to the TestSprite MCP instead of failing on localhost

Maintainers: merge with a merge commit (no squash / no rebase).

Summary by CodeRabbit

  • New Features
    • Added test cancel for cancelling one or multiple runs.
    • Added confirmed project delete with dry-run support.
    • Added backend dependency metadata and execution artifacts to test details and results.
    • Added V2/V3 routing visibility and guidance.
  • Bug Fixes
    • Ctrl-C and termination signals now gracefully detach from waiting commands while preserving partial results and re-attach options.
    • Improved frontend failure selection and backend step summaries.
  • Documentation
    • Updated CLI references, release notes, Windows development guidance, and version compatibility details.

Private-Snapshot-RevId: afa3bf501545df536cfa638a86ae096fb7c34880
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The release updates the CLI to 0.4.0 with project deletion, run cancellation, graceful signal detachment, backend metadata and artifact rendering, minimum-version handling, V3 routing visibility, Windows CI support, secret scanning, and expanded release documentation.

Changes

CLI behavior and runtime

Layer / File(s) Summary
Project deletion and run cancellation
src/commands/project.ts, src/commands/test.ts, src/lib/http.ts
Adds confirmed project deletion and single- or multi-run cancellation with idempotency, dry-run support, summaries, and conflict handling.
Graceful shutdown and polling
src/lib/interrupt.ts, src/lib/http.ts, src/lib/poll.ts, src/index.ts
Propagates termination signals through polling and HTTP requests, preserves partial output, and reports signal-specific exit codes.
Backend metadata and compatibility
src/commands/test.ts, src/lib/version-notice.ts, src/lib/v3-advisory.ts, src/commands/doctor.ts, src/commands/auth.ts
Adds dependency metadata, backend artifacts, minimum-version notices, and V2/V3 routing output and advisories.
CI and release automation
.github/workflows/*, .gitleaks.toml, package.json, src/version.ts
Adds Windows tests, gitleaks scanning, credential-safe checkouts, pinned npm publishing, backport dispatch, and version 0.4.0 metadata.
Documentation and platform support
DOCUMENTATION.md, README.md, CONTRIBUTING.md, CHANGELOG.md, src/lib/bundle.ts, test/helpers/execNpm.ts
Documents new commands and runtime behavior, adds Windows path handling, and uses a cross-platform npm test helper.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: zeshi-du

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.83% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies this as the v0.4.0 release, matching the PR’s main purpose.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/v0.4.0

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@github-actions

Copy link
Copy Markdown

Test Coverage Report

Metric Coverage
Lines 86.77%
Statements 86.77%
Functions 81.15%
Branches 85.45%

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

Caution

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

⚠️ Outside diff range comments (1)
src/commands/test.ts (1)

1400-1428: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Support clearing backend dependency declarations.

The update path treats empty arrays as “not supplied,” so users cannot remove existing declarations.

  • src/commands/test.ts#L1400-L1428: add explicit clear semantics and send produces: [] / consumes: [] when requested.
  • src/commands/test.test.ts#L6359-L6379: replace the omission assertion with coverage for clearing existing declarations.

As per path instructions, backend dependency declarations must be editable via test update.

🤖 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/commands/test.ts` around lines 1400 - 1428, Update the test update option
handling in src/commands/test.ts lines 1400-1428 to distinguish omitted
dependency arrays from explicitly provided empty arrays, allowing produces: []
and consumes: [] to be sent for clearing; preserve validation requiring at least
one supplied field and map opts.needs to consumes. In src/commands/test.test.ts
lines 6359-6379, replace the omission assertion with coverage verifying existing
backend dependency declarations are cleared by sending empty produces and
consumes arrays.

Source: Path instructions

🤖 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/commands/doctor.ts`:
- Around line 123-125: Update the V3-enabled branch in the doctor command to
call emitV3RoutingAdvisory only when output mode is text, suppressing it for
JSON output. Add a regression test covering JSON output with V3 enabled and
retain the advisory for text mode.

In `@src/commands/test.run.spec.ts`:
- Line 3895: Replace the 5 ms setTimeout in the polling test with a startup
synchronization promise resolved when the polling GET/fetch begins; await that
promise before calling shutdown.interrupt('SIGINT'), ensuring the abort listener
is installed and removing the real-timer dependency.

In `@src/commands/test.ts`:
- Around line 5992-6033: Update the multi-run cancellation flow around the row
error handling, `summary.errors`, and exit-precedence checks to retain each
typed error’s documented exit code instead of always throwing `CLIError` with
code 1. Store the relevant exit code with each error row, then select and apply
a deterministic precedence when multiple failures occur, while preserving the
existing notFound precedence and error reporting.
- Around line 10391-10409: The appendArtifactTail function currently limits
output by lines but can emit an oversized single line. Add a byte/character cap
to the artifact value before splitting, preserving the tail-oriented behavior
and ensuring text output remains bounded; update the reported byte count and
omitted-content indication to reflect the bounded output while retaining the
full-content reference for JSON.

In `@src/lib/poll.spec.ts`:
- Around line 852-853: Replace elapsed-time waits with mock-readiness promises
before calling shutdown.interrupt. In src/lib/poll.spec.ts at 852-853, signal
when neverSleep is entered; in src/lib/http.test.ts at 853-854 and 878-879,
signal when each retry sleep begins; in src/commands/test.wait.spec.ts at
1356-1359 and 1397-1398, signal when hangingFetch receives the request and reuse
that barrier; in src/commands/test.quickwins.spec.ts at 1029-1032 and
src/commands/test.rerun.spec.ts at 4959-4963, await barriers confirming both
polls are in flight before interrupting.

In `@test/e2e/signal.e2e.test.ts`:
- Line 107: Remove the hardcoded setTimeout delay in the signal-handling test
after await arrived. Use the existing arrived synchronization as the readiness
guarantee before continuing, keeping the test deterministic and free of real
timers.

---

Outside diff comments:
In `@src/commands/test.ts`:
- Around line 1400-1428: Update the test update option handling in
src/commands/test.ts lines 1400-1428 to distinguish omitted dependency arrays
from explicitly provided empty arrays, allowing produces: [] and consumes: [] to
be sent for clearing; preserve validation requiring at least one supplied field
and map opts.needs to consumes. In src/commands/test.test.ts lines 6359-6379,
replace the omission assertion with coverage verifying existing backend
dependency declarations are cleared by sending empty produces and consumes
arrays.
🪄 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: 3509dc37-fbca-4396-b1da-be6775721dee

📥 Commits

Reviewing files that changed from the base of the PR and between 60d55e4 and e91c5a1.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
  • test/__snapshots__/help.snapshot.test.ts.snap is excluded by !**/*.snap, !**/*.snap
📒 Files selected for processing (56)
  • .github/workflows/backport-dispatch.yml
  • .github/workflows/ci-nudge.yml
  • .github/workflows/ci.yml
  • .github/workflows/issue-triage.yml
  • .github/workflows/pr-triage.yml
  • .github/workflows/release.yaml
  • .github/workflows/test-coverage.yml
  • .gitleaks.toml
  • CHANGELOG.md
  • CONTRIBUTING.md
  • DOCUMENTATION.md
  • README.md
  • package.json
  • scripts/README.md
  • skills/testsprite-verify.codex.md
  • skills/testsprite-verify.skill.md
  • src/commands/agent.test.ts
  • src/commands/auth.test.ts
  • src/commands/auth.ts
  • src/commands/doctor.test.ts
  • src/commands/doctor.ts
  • src/commands/project.test.ts
  • src/commands/project.ts
  • src/commands/test.cancel.spec.ts
  • src/commands/test.quickwins.spec.ts
  • src/commands/test.rerun.spec.ts
  • src/commands/test.run.spec.ts
  • src/commands/test.test.ts
  • src/commands/test.ts
  • src/commands/test.wait.spec.ts
  • src/index.ts
  • src/lib/bundle.test.ts
  • src/lib/bundle.ts
  • src/lib/client-factory.ts
  • src/lib/dry-run/samples.test.ts
  • src/lib/dry-run/samples.ts
  • src/lib/errors.test.ts
  • src/lib/errors.ts
  • src/lib/failing-fe-resolver.spec.ts
  • src/lib/failing-fe-resolver.ts
  • src/lib/http.test.ts
  • src/lib/http.ts
  • src/lib/interrupt.test.ts
  • src/lib/interrupt.ts
  • src/lib/poll.spec.ts
  • src/lib/poll.ts
  • src/lib/runs.types.ts
  • src/lib/v3-advisory.test.ts
  • src/lib/v3-advisory.ts
  • src/lib/version-notice.test.ts
  • src/lib/version-notice.ts
  • src/version.ts
  • test/cli.subprocess.test.ts
  • test/e2e/signal.e2e.test.ts
  • test/help.snapshot.test.ts
  • test/helpers/execNpm.ts

Comment thread src/commands/doctor.ts
Comment on lines +123 to +125
if (connectivity.v3Enabled === true) {
emitV3RoutingAdvisory(stderr);
}

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

Suppress the V3 advisory in JSON mode.

doctor --output json currently emits plain-text advisory lines to stderr, unlike auth status. Gate this call on text mode and add a JSON/V3 regression test.

Proposed fix
-  if (connectivity.v3Enabled === true) {
+  if (opts.output !== 'json' && connectivity.v3Enabled === true) {
     emitV3RoutingAdvisory(stderr);
   }

As per path instructions, the V3 routing advisory must be emitted “in the V3-enabled case, text-mode only.”

📝 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
if (connectivity.v3Enabled === true) {
emitV3RoutingAdvisory(stderr);
}
if (opts.output !== 'json' && connectivity.v3Enabled === true) {
emitV3RoutingAdvisory(stderr);
}
🤖 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/commands/doctor.ts` around lines 123 - 125, Update the V3-enabled branch
in the doctor command to call emitV3RoutingAdvisory only when output mode is
text, suppressing it for JSON output. Add a regression test covering JSON output
with V3 enabled and retain the advisory for text mode.

Source: Path instructions

shutdown,
},
);
setTimeout(() => shutdown.interrupt('SIGINT'), 5);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Synchronize on poll startup instead of sleeping for 5 ms.

The real timer can fire before the GET installs its abort listener, making this test timing-dependent. Resolve a promise when the polling fetch starts, await it, then call shutdown.interrupt('SIGINT').

As per path instructions, tests must be deterministic and use no real timers.

🤖 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/commands/test.run.spec.ts` at line 3895, Replace the 5 ms setTimeout in
the polling test with a startup synchronization promise resolved when the
polling GET/fetch begins; await that promise before calling
shutdown.interrupt('SIGINT'), ensuring the abort listener is installed and
removing the real-timer dependency.

Source: Path instructions

Comment thread src/commands/test.ts
Comment on lines +5992 to +6033
const message = err instanceof Error ? err.message : String(err);
rows.push({ runId, status: 'error', error: message });
}
}

const errorRows = rows.filter(r => r.status === 'error');
const summary: CliCancelSummary = {
cancelled: rows.filter(r => r.status === 'cancelled').map(r => r.runId),
alreadyCancelled: rows.filter(r => r.status === 'alreadyCancelled').map(r => r.runId),
conflicts: rows
.filter(r => r.status === 'conflict')
.map(r => ({ runId: r.runId, status: r.conflictStatus ?? 'unknown' })),
notFound: rows.filter(r => r.status === 'notFound').map(r => r.runId),
errors: errorRows.map(r => ({ runId: r.runId, message: r.error ?? 'unknown error' })),
};

out.print(summary, data => renderCancelSummaryText(data as CliCancelSummary));

const parts = [
`${summary.cancelled.length} cancelled`,
`${summary.alreadyCancelled.length} already cancelled`,
];
if (summary.conflicts.length > 0) parts.push(`${summary.conflicts.length} conflict`);
if (summary.notFound.length > 0) parts.push(`${summary.notFound.length} not found`);
if (errorRows.length > 0) parts.push(`${errorRows.length} error`);
stderrFn(`Cancel summary: ${parts.join(', ')}.`);

// Exit precedence (CXL-11): notFound outranks conflict — a caller-side bug
// (wrong id / wrong tenant) is more actionable to surface than "it already
// finished". A bare transport/auth error on any member also fails loudly
// rather than being silently absorbed into a 0 exit.
if (summary.notFound.length > 0) {
throw new CLIError(
`${summary.notFound.length} run id${summary.notFound.length !== 1 ? 's' : ''} not found: ${summary.notFound.join(' ')}`,
4,
);
}
if (errorRows.length > 0) {
throw new CLIError(
`${errorRows.length} cancel request${errorRows.length !== 1 ? 's' : ''} failed: ${errorRows.map(r => r.runId).join(' ')}`,
1,
);

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

Preserve documented exit codes for multi-run cancellation failures.

Auth, transport, HTTP 426, and other typed errors are flattened into exit code 1. Retain each error’s documented exit code and define deterministic precedence rather than introducing this ad-hoc code.

As per path instructions, error paths must map to the documented exit code and must not introduce ad-hoc codes.

🤖 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/commands/test.ts` around lines 5992 - 6033, Update the multi-run
cancellation flow around the row error handling, `summary.errors`, and
exit-precedence checks to retain each typed error’s documented exit code instead
of always throwing `CLIError` with code 1. Store the relevant exit code with
each error row, then select and apply a deterministic precedence when multiple
failures occur, while preserving the existing notFound precedence and error
reporting.

Source: Path instructions

Comment thread src/commands/test.ts
Comment on lines +10391 to +10409
const BACKEND_ARTIFACT_TAIL_LINES = 20;

function appendArtifactTail(
lines: string[],
label: string,
value: string | null | undefined,
): void {
if (value == null || value === '') return;
const allLines = value.replace(/\n+$/, '').split('\n');
const dropped = Math.max(0, allLines.length - BACKEND_ARTIFACT_TAIL_LINES);
const tail = dropped > 0 ? allLines.slice(-BACKEND_ARTIFACT_TAIL_LINES) : allLines;
const bytes = Buffer.byteLength(value, 'utf8');
lines.push('');
lines.push(
`${label} (${bytes} bytes${dropped > 0 ? `, showing last ${tail.length} lines` : ''}):`,
);
for (const l of tail) lines.push(` ${l}`);
if (dropped > 0)
lines.push(` … ${dropped} earlier line(s) omitted — full content in --output json`);

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

Bound artifact tails by bytes as well as lines.

A single 50-KB line bypasses the 20-line limit and is printed in full. Apply a byte/character tail cap before splitting into lines.

Proposed direction
 const BACKEND_ARTIFACT_TAIL_LINES = 20;
+const BACKEND_ARTIFACT_TAIL_BYTES = 8 * 1024;

-  const allLines = value.replace(/\n+$/, '').split('\n');
+  const valueBuffer = Buffer.from(value, 'utf8');
+  const bounded =
+    valueBuffer.length > BACKEND_ARTIFACT_TAIL_BYTES
+      ? valueBuffer.subarray(-BACKEND_ARTIFACT_TAIL_BYTES).toString('utf8')
+      : value;
+  const allLines = bounded.replace(/\n+$/, '').split('\n');

As per path instructions, text output must print a bounded tail with byte counts.

📝 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
const BACKEND_ARTIFACT_TAIL_LINES = 20;
function appendArtifactTail(
lines: string[],
label: string,
value: string | null | undefined,
): void {
if (value == null || value === '') return;
const allLines = value.replace(/\n+$/, '').split('\n');
const dropped = Math.max(0, allLines.length - BACKEND_ARTIFACT_TAIL_LINES);
const tail = dropped > 0 ? allLines.slice(-BACKEND_ARTIFACT_TAIL_LINES) : allLines;
const bytes = Buffer.byteLength(value, 'utf8');
lines.push('');
lines.push(
`${label} (${bytes} bytes${dropped > 0 ? `, showing last ${tail.length} lines` : ''}):`,
);
for (const l of tail) lines.push(` ${l}`);
if (dropped > 0)
lines.push(` … ${dropped} earlier line(s) omitted — full content in --output json`);
const BACKEND_ARTIFACT_TAIL_LINES = 20;
const BACKEND_ARTIFACT_TAIL_BYTES = 8 * 1024;
function appendArtifactTail(
lines: string[],
label: string,
value: string | null | undefined,
): void {
if (value == null || value === '') return;
const valueBuffer = Buffer.from(value, 'utf8');
const bounded =
valueBuffer.length > BACKEND_ARTIFACT_TAIL_BYTES
? valueBuffer.subarray(-BACKEND_ARTIFACT_TAIL_BYTES).toString('utf8')
: value;
const allLines = bounded.replace(/\n+$/, '').split('\n');
const dropped = Math.max(0, allLines.length - BACKEND_ARTIFACT_TAIL_LINES);
const tail = dropped > 0 ? allLines.slice(-BACKEND_ARTIFACT_TAIL_LINES) : allLines;
const bytes = Buffer.byteLength(value, 'utf8');
lines.push('');
lines.push(
`${label} (${bytes} bytes${dropped > 0 ? `, showing last ${tail.length} lines` : ''}):`,
);
for (const l of tail) lines.push(` ${l}`);
if (dropped > 0)
lines.push(` … ${dropped} earlier line(s) omitted — full content in --output json`);
}
🤖 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/commands/test.ts` around lines 10391 - 10409, The appendArtifactTail
function currently limits output by lines but can emit an oversized single line.
Add a byte/character cap to the artifact value before splitting, preserving the
tail-oriented behavior and ensuring text output remains bounded; update the
reported byte count and omitted-content indication to reflect the bounded output
while retaining the full-content reference for JSON.

Source: Path instructions

Comment thread src/lib/poll.spec.ts
Comment on lines +852 to +853
await new Promise(resolve => setTimeout(resolve, 10)); // let the loop reach the sleep
shutdown.interrupt('SIGTERM');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Synchronize on mock readiness instead of elapsed time.

Fixed 5–25 ms delays can interrupt before the mocked fetch/sleep is reached on slow CI. Resolve a promise from the mock when it starts, await that barrier, then call shutdown.interrupt(...).

  • src/lib/poll.spec.ts#L852-L853: signal when neverSleep is entered.
  • src/lib/http.test.ts#L853-L854: signal when retry sleep starts.
  • src/lib/http.test.ts#L878-L879: signal when Retry-After sleep starts.
  • src/commands/test.wait.spec.ts#L1356-L1359: signal when hangingFetch receives the request.
  • src/commands/test.wait.spec.ts#L1397-L1398: use the same fetch-start barrier.
  • src/commands/test.quickwins.spec.ts#L1029-L1032: wait until both run polls are in flight.
  • src/commands/test.rerun.spec.ts#L4959-L4963: wait until both accepted-run polls are in flight.
📍 Affects 5 files
  • src/lib/poll.spec.ts#L852-L853 (this comment)
  • src/lib/http.test.ts#L853-L854
  • src/lib/http.test.ts#L878-L879
  • src/commands/test.wait.spec.ts#L1356-L1359
  • src/commands/test.wait.spec.ts#L1397-L1398
  • src/commands/test.quickwins.spec.ts#L1029-L1032
  • src/commands/test.rerun.spec.ts#L4959-L4963
🤖 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/lib/poll.spec.ts` around lines 852 - 853, Replace elapsed-time waits with
mock-readiness promises before calling shutdown.interrupt. In
src/lib/poll.spec.ts at 852-853, signal when neverSleep is entered; in
src/lib/http.test.ts at 853-854 and 878-879, signal when each retry sleep
begins; in src/commands/test.wait.spec.ts at 1356-1359 and 1397-1398, signal
when hangingFetch receives the request and reuse that barrier; in
src/commands/test.quickwins.spec.ts at 1029-1032 and
src/commands/test.rerun.spec.ts at 4959-4963, await barriers confirming both
polls are in flight before interrupting.

);

await arrived; // the long-poll fetch is in flight — the armed window is open
await new Promise(r => setTimeout(r, 150)); // let the request settle into the poll loop

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Avoid real timers in tests.

As per path instructions, tests must be deterministic and offline with no real timers. Using a hardcoded setTimeout of 150ms to wait for the child process to settle can lead to flaky tests in slower CI environments.

Since the CLI must arm the signal handler before initiating the HTTP request, the fact that the request has arrived at the server (await arrived) already guarantees the handler is active. You can likely safely remove this sleep altogether.

♻️ Proposed fix
-  await new Promise(r => setTimeout(r, 150)); // let the request settle into the poll loop
📝 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
await new Promise(r => setTimeout(r, 150)); // let the request settle into the poll loop
🤖 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 `@test/e2e/signal.e2e.test.ts` at line 107, Remove the hardcoded setTimeout
delay in the signal-handling test after await arrived. Use the existing arrived
synchronization as the readiness guarantee before continuing, keeping the test
deterministic and free of real timers.

Source: Path instructions

@zeshi-du zeshi-du 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.

Reviewed against the atlas snapshot source (release/public @ afa3bf5) — approving.

Integrity: PR head = the snapshot source minus exactly the sanctioned internal drops (dev-e2e tier, mock-backend internals, perf scripts, internal docs). The five deliberate divergences are all go-public transforms: internal-only npm scripts stripped, GitHub Packages restricted → public npm, :11443 dev endpoints scrubbed to prod URLs in contract/mock fixtures, and the reworked release.yaml (SHA-pinned actions, id-token: write provenance, exact npm@11.6.2 pin with the sigstore/npm-12.0.0 rationale documented — nice work, this is the DEV-321 root-cause fix).

Security: gitleaks green + manual pattern sweep (internal ports/hostnames/keys) zero hits. The new backport-dispatch.yml is a checkout-free pull_request_target reading event metadata only, contents: read, no-op until an operator arms the App secret — safe as written; keep the "do not add actions/checkout" invariant.

CI: every substantive check green incl. Windows + Node 22. The red gate check is the repo-wide broken issue-link gate (@actions/github module resolution — fails on ~16 open PRs regardless of content; community PR #257 fixes it) — not a content signal.

Heads-up, non-blocking: this cut does not include today's DEV-404 fix (agent install <target> positional silently installs the claude skill — atlas #280, in review), which the v0.4.0 validation flagged as fix-before-tag-recommended. It rides 0.4.1 unless we respin. Also note the first v* tag will be the first real exercise of the OIDC provenance path — watch the publish job.

@fyZhang66
fyZhang66 merged commit 7b4937b into main Jul 17, 2026
11 of 13 checks passed
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.

2 participants