Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
target/
node_modules/
.worktrees/
*.node
.DS_Store

Expand Down
47 changes: 39 additions & 8 deletions crates/cli/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,22 +951,53 @@ fn fetch_invalid_url_json() {
assert_eq!(v["code"], "INVALID_INPUT");
}

const MAX_REQUEST_HEADERS_SIZE: usize = 32 * 1024;

fn read_request(stream: &mut TcpStream) -> String {
stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap();
let mut request_line = Vec::with_capacity(128);
loop {
let mut request = Vec::with_capacity(512);
while !request.ends_with(b"\r\n\r\n") {
let mut byte = [0_u8; 1];
stream.read_exact(&mut byte).unwrap();
request_line.push(byte[0]);
if byte[0] == b'\n' {
break;
}
assert!(request_line.len() < 8_192, "HTTP request line is unexpectedly long");
request.push(byte[0]);
assert!(
request.len() <= MAX_REQUEST_HEADERS_SIZE,
"HTTP request headers are unexpectedly large"
);
}
let request_line = String::from_utf8_lossy(&request_line);

let request_line = request.split(|byte| *byte == b'\n').next().unwrap_or_default();
let request_line = String::from_utf8_lossy(request_line);
request_line.split_whitespace().nth(1).unwrap_or_default().to_string()
}

#[test]
fn read_request_waits_for_complete_headers() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let address = listener.local_addr().unwrap();
let (accepted_sender, accepted_receiver) = mpsc::channel();
let (path_sender, path_receiver) = mpsc::channel();
let server = thread::spawn(move || {
let (mut stream, _) = listener.accept().unwrap();
accepted_sender.send(()).unwrap();
path_sender.send(read_request(&mut stream)).unwrap();
});

let mut client = TcpStream::connect(address).unwrap();
accepted_receiver.recv_timeout(Duration::from_secs(2)).unwrap();
client.write_all(b"GET /complete HTTP/1.1\r\n").unwrap();
client.flush().unwrap();

assert!(
path_receiver.recv_timeout(Duration::from_millis(100)).is_err(),
"request completed before the header terminator"
);

client.write_all(b"Host: localhost\r\nConnection: close\r\n\r\n").unwrap();
assert_eq!(path_receiver.recv_timeout(Duration::from_secs(2)).unwrap(), "/complete");
server.join().unwrap();
}

fn response(status: &str, headers: &[(&str, &str)], body: &str) -> String {
let mut response = format!("HTTP/1.1 {status}\r\nContent-Length: {}\r\n", body.len());
for (name, value) in headers {
Expand Down
240 changes: 240 additions & 0 deletions docs/superpowers/plans/2026-07-14-js-dependencies-fetch-fixture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
# JavaScript Dependencies and Fetch Fixture Stability Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Update the root JavaScript tooling and eliminate intermittent Windows fetch-test socket resets without changing production behavior.

**Architecture:** Keep the dependency refresh isolated to `package.json` and `pnpm-lock.yaml`. Correct the test-only HTTP fixture by reading a complete header block before responding, with a deterministic test that proves the helper does not return after only a request line.

**Tech Stack:** Rust 2024, standard-library TCP sockets and channels, Cargo tests, pnpm, fallow, oxfmt, oxlint, GitHub Actions, CodSpeed.

## Global Constraints

- Keep production fetch behavior unchanged.
- Add no HTTP mock-server dependency.
- Do not increase timeouts to hide the socket reset.
- Preserve `memchr` 2.8.2 because 2.8.3 failed the performance gate.
- Use signed conventional commits.

## File Structure

- Modify `crates/cli/tests/cli.rs`: deterministic fixture regression test and complete-header request reader.
- Modify `package.json`: exact root tooling versions.
- Modify `pnpm-lock.yaml`: regenerated dependency graph.
- Create `docs/superpowers/plans/2026-07-14-js-dependencies-fetch-fixture.md`: execution record.

---

### Task 1: Consume Complete HTTP Fixture Requests

**Files:**
- Modify and test: `crates/cli/tests/cli.rs:950-1015`

**Interfaces:**
- Consumes: `TcpListener`, `TcpStream`, `mpsc`, `Duration`, and the existing `read_request(&mut TcpStream) -> String` helper.
- Produces: the same `read_request(&mut TcpStream) -> String` interface, now returning only after `\r\n\r\n` has been consumed.

- [ ] **Step 1: Add the deterministic failing test after `read_request`**

```rust
#[test]
fn read_request_waits_for_complete_headers() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let address = listener.local_addr().unwrap();
let (accepted_sender, accepted_receiver) = mpsc::channel();
let (path_sender, path_receiver) = mpsc::channel();
let server = thread::spawn(move || {
let (mut stream, _) = listener.accept().unwrap();
accepted_sender.send(()).unwrap();
path_sender.send(read_request(&mut stream)).unwrap();
});

let mut client = TcpStream::connect(address).unwrap();
accepted_receiver.recv_timeout(Duration::from_secs(2)).unwrap();
client.write_all(b"GET /complete HTTP/1.1\r\n").unwrap();
client.flush().unwrap();

assert!(
path_receiver.recv_timeout(Duration::from_millis(100)).is_err(),
"request completed before the header terminator"
);

client.write_all(b"Host: localhost\r\nConnection: close\r\n\r\n").unwrap();
assert_eq!(path_receiver.recv_timeout(Duration::from_secs(2)).unwrap(), "/complete");
server.join().unwrap();
}
```

- [ ] **Step 2: Run the focused test and verify red**

Run:

```bash
cargo test -p srcmap-cli --test cli read_request_waits_for_complete_headers -- --exact
```

Expected: FAIL with `request completed before the header terminator`.

- [ ] **Step 3: Replace request-line-only reading with bounded complete-header reading**

```rust
const MAX_REQUEST_HEADERS_SIZE: usize = 32 * 1024;

fn read_request(stream: &mut TcpStream) -> String {
stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap();
let mut request = Vec::with_capacity(512);
while !request.ends_with(b"\r\n\r\n") {
let mut byte = [0_u8; 1];
stream.read_exact(&mut byte).unwrap();
request.push(byte[0]);
assert!(
request.len() <= MAX_REQUEST_HEADERS_SIZE,
"HTTP request headers are unexpectedly large"
);
}

let request_line = request.split(|byte| *byte == b'\n').next().unwrap_or_default();
let request_line = String::from_utf8_lossy(request_line);
request_line.split_whitespace().nth(1).unwrap_or_default().to_string()
}
```

- [ ] **Step 4: Run the focused test and fetch integration tests**

Run:

```bash
cargo test -p srcmap-cli --test cli read_request_waits_for_complete_headers -- --exact
cargo test -p srcmap-cli --test cli fetch_
```

Expected: PASS.

- [ ] **Step 5: Run a local stress loop**

Run:

```bash
for run in {1..25}; do cargo test -q -p srcmap-cli --test cli fetch_ || exit 1; done
```

Expected: every iteration exits successfully.

- [ ] **Step 6: Commit the fixture fix**

```bash
git add crates/cli/tests/cli.rs
git commit -S -m "test: consume complete fixture requests"
```

### Task 2: Update Root JavaScript Tooling

**Files:**
- Modify: `package.json:40-44`
- Modify: `pnpm-lock.yaml`

**Interfaces:**
- Consumes: existing root scripts for fallow, oxfmt, and oxlint.
- Produces: exact versions `fallow` 3.5.0, `oxfmt` 0.59.0, and `oxlint` 1.74.0 with a frozen-install-compatible lockfile.

- [ ] **Step 1: Update exact manifest versions**

```json
"devDependencies": {
"fallow": "3.5.0",
"oxfmt": "0.59.0",
"oxlint": "1.74.0"
}
```

- [ ] **Step 2: Regenerate the lockfile without running package scripts**

Run:

```bash
pnpm install --lockfile-only --ignore-scripts
```

Expected: `package.json` and `pnpm-lock.yaml` resolve the three requested versions.

- [ ] **Step 3: Verify the updated tools**

Run:

```bash
pnpm run fmt:js:check
pnpm run lint:js
pnpm outdated --format list
```

Expected: formatting and linting pass, with no newer direct JavaScript dependency reported.

- [ ] **Step 4: Review dependency scope and preserve the Rust lock selection**

Run:

```bash
git diff -- package.json pnpm-lock.yaml
rg -n 'name = "memchr"|version = "2\.8\.2"' Cargo.lock
```

Expected: only the requested JavaScript tooling graph changes and `memchr` remains at 2.8.2.

- [ ] **Step 5: Commit the dependency update**

```bash
git add package.json pnpm-lock.yaml
git commit -S -m "chore: update JavaScript tooling"
```

### Task 3: Full Verification and Publication

**Files:**
- Verify all files changed since `origin/main`.

**Interfaces:**
- Consumes: completed Tasks 1 and 2.
- Produces: a clean pull request with passing local and remote validation, merged to `main`.

- [ ] **Step 1: Run full local verification with bounded logs**

```bash
pnpm check > /tmp/srcmap-js-fixture-check.log 2>&1
pnpm test > /tmp/srcmap-js-fixture-test.log 2>&1
```

Expected: both commands exit successfully.

- [ ] **Step 2: Review the complete diff and repository state**

```bash
git diff --check origin/main...HEAD
git diff --stat origin/main...HEAD
git status --short --branch
git log --show-signature --format=fuller origin/main..HEAD
```

Expected: only the design, plan, fixture test helper, dependency manifest, and lockfile are changed; commits have valid signatures.

- [ ] **Step 3: Push and create a ready pull request**

```bash
git push -u origin codex/update-js-stabilize-fetch-tests
gh pr create --base main --head codex/update-js-stabilize-fetch-tests --title "test: stabilize fetch fixtures and update JS tooling" --body-file /tmp/srcmap-js-fixture-pr.md
```

Expected: a ready pull request is created.

- [ ] **Step 4: Require all PR checks**

Run `gh pr checks --watch` and inspect any failure before retrying or fixing it.

Expected: Windows CI, security, coverage, and CodSpeed pass.

- [ ] **Step 5: Squash merge and verify the exact merge commit**

```bash
gh pr merge --squash --delete-branch --subject "test: stabilize fetch fixtures and update JS tooling"
```

Expected: the pull request is merged, local `main` matches `origin/main`, and every workflow for the merge commit completes successfully.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# JavaScript Dependencies and Fetch Fixture Stability

## Context

The root JavaScript tooling dependencies have newer releases available:

- `fallow` 3.5.0
- `oxfmt` 0.59.0
- `oxlint` 1.74.0

Separately, Windows CI intermittently times out while fetch integration tests wait for a second local HTTP request. The local fixture currently reads only the request line before writing a response and closing the socket. Unread request headers can cause Windows to reset the connection, so the client treats the first request as failed and never sends the expected second request.

## Goals

- Update the three root JavaScript tooling dependencies to their current exact versions.
- Make the local HTTP fixture consume a complete request header block before responding.
- Prove the fixture behavior with a deterministic regression test.
- Keep production fetch behavior unchanged.
- Preserve the intentional `memchr` 2.8.2 lockfile selection because 2.8.3 failed the performance gate.

## Non-goals

- Refactor the production fetch implementation.
- Add an HTTP mock-server dependency.
- Increase timeouts to hide the socket reset.
- Change unrelated test infrastructure.

## Design

### Dependency update

Update the exact versions in the root `package.json`, regenerate `pnpm-lock.yaml`, and run the existing formatting, linting, analysis, and test commands. No package scripts or configuration should change unless a new tool version exposes a real incompatibility.

### HTTP fixture

Change `read_request` in `crates/cli/tests/cli.rs` to read bytes until the HTTP header terminator `\r\n\r\n`. Retain the first request line for path parsing and reject an unexpectedly large header block with a named size limit.

This ensures the server has consumed the client's request data before it writes a response and drops the connection. The fixture remains dependency-free and continues to support only the GET requests needed by these tests.

### Regression test

Add a fixture-level test that opens a loopback connection and sends the request in two stages:

1. Send only the request line and verify `read_request` has not completed.
2. Send headers and the terminating blank line.
3. Verify `read_request` completes and returns the expected path.

The test must fail against the current request-line-only implementation before the helper is changed. It must pass after the complete-header implementation is added.

## Verification

- Run the focused regression test and record the expected red then green result.
- Repeatedly run the fetch integration tests to exercise the fixture.
- Run `pnpm check` and `pnpm test`.
- Confirm the lockfile has no unexpected dependency changes.
- Push a pull request and require Windows CI, security checks, coverage, and CodSpeed to pass.
- After merge, verify every workflow for the exact merge commit on `main`.

## Rollout

Land the dependency update and fixture fix together because the test-only fix removes the CI flake that could otherwise obscure validation of the dependency update. If a tooling update causes a separate failure, isolate that compatibility change in its own commit before merging.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
"coverage:rust:html": "cargo llvm-cov --html"
},
"devDependencies": {
"fallow": "3.4.2",
"oxfmt": "0.58.0",
"oxlint": "1.73.0"
"fallow": "3.5.0",
"oxfmt": "0.59.0",
"oxlint": "1.74.0"
},
"packageManager": "pnpm@10.33.0"
}
Loading
Loading