diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 568fb9c..9e743bd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -13,6 +13,10 @@ updates: patterns: ["napi", "napi-derive", "napi-build"] wasm-bindgen: patterns: ["wasm-bindgen", "js-sys"] + ignore: + # memchr 2.8.3 regressed the performance gate; retry with the next release. + - dependency-name: memchr + versions: ["2.8.3"] open-pull-requests-limit: 10 - package-ecosystem: npm diff --git a/.github/scripts/workflow-policy.test.mjs b/.github/scripts/workflow-policy.test.mjs index 191f3e9..42968a0 100644 --- a/.github/scripts/workflow-policy.test.mjs +++ b/.github/scripts/workflow-policy.test.mjs @@ -5,11 +5,15 @@ import { describe, it } from "node:test"; const ROOT_URL = new URL("../../", import.meta.url); const WORKFLOWS_URL = new URL("workflows/", new URL("../", import.meta.url)); +const BENCH_WORKFLOW_URL = new URL("bench.yml", WORKFLOWS_URL); const CI_WORKFLOW_URL = new URL("ci.yml", WORKFLOWS_URL); const COVERAGE_WORKFLOW_URL = new URL("coverage.yml", WORKFLOWS_URL); const RELEASE_WORKFLOW_URL = new URL("release.yml", WORKFLOWS_URL); +const CONTRIBUTING_URL = new URL("CONTRIBUTING.md", ROOT_URL); +const DEPENDABOT_CONFIG_URL = new URL(".github/dependabot.yml", ROOT_URL); const FALLOW_CONFIG_URL = new URL(".fallowrc.json", ROOT_URL); const PACKAGE_JSON_URL = new URL("package.json", ROOT_URL); +const README_URL = new URL("README.md", ROOT_URL); const WASM_PACK_INSTALL_ACTION = "taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853"; const WASM_PACK_WORKFLOWS = new Map([ ["bench.yml", " if: matrix.kind == 'node'\n"], @@ -70,6 +74,19 @@ const workflowJob = (workflow, jobName) => { return nextJob === -1 ? remaining : remaining.slice(0, nextJob); }; +const assertSafeNapiConsumer = (name, contents) => { + const unsafeBuilds = [ + /\bnapi build\b/, + /\bpnpm\b[^\n]*--filter @srcmap\/(?:codec|sourcemap)(?=\s)[^\n]*\bbuild\b/, + /\b(?:cd|working-directory:)\s+packages\/(?:codec|sourcemap)(?=\s|$)/m, + /\bpnpm\b[^\n]*--dir\s+packages\/(?:codec|sourcemap)(?=\s)[^\n]*\bbuild\b/, + ]; + + for (const unsafeBuild of unsafeBuilds) { + assert.doesNotMatch(contents, unsafeBuild, `${name}: use the no-js bootstrap`); + } +}; + describe("JavaScript dependency policy", () => { it("keeps pnpm-lock.yaml as the only tracked JavaScript lockfile", async () => { assert.deepEqual(await trackedPackageLocks(), []); @@ -120,6 +137,50 @@ describe("Generated artifact policy", () => { ); assert.doesNotMatch(job, /corepack pnpm --filter @srcmap\/.+ build/); }); + + it("keeps every non-release NAPI consumer on the no-js bootstrap", async () => { + const ci = await readFile(CI_WORKFLOW_URL, "utf8"); + const coverage = await readFile(COVERAGE_WORKFLOW_URL, "utf8"); + const bench = await readFile(BENCH_WORKFLOW_URL, "utf8"); + const contributing = await readFile(CONTRIBUTING_URL, "utf8"); + const readme = await readFile(README_URL, "utf8"); + assert.match(workflowJob(ci, "js-runtime"), /corepack pnpm run build:test-artifacts/); + assert.match(workflowJob(coverage, "coverage"), /corepack pnpm run build:test-artifacts:napi/); + assert.match(bench, /corepack pnpm run build:test-artifacts:napi/); + assert.match(contributing, /corepack pnpm run build:test-artifacts:napi/); + assert.match(readme, /corepack pnpm run build:test-artifacts:napi/); + + for (const [name, contents] of [ + ["ci.yml", ci], + ["coverage.yml", coverage], + ["bench.yml", bench], + ["CONTRIBUTING.md", contributing], + ["README.md", readme], + ]) { + assertSafeNapiConsumer(name, contents); + } + }); + + it("rejects direct and package-local NAPI build variants", () => { + for (const unsafeBuild of [ + "corepack pnpm exec napi build --release", + "run: corepack pnpm run build\nworking-directory: packages/codec", + "corepack pnpm --dir packages/sourcemap run build", + ]) { + assert.throws(() => assertSafeNapiConsumer("fixture", unsafeBuild)); + } + }); +}); + +describe("Dependabot policy", () => { + it("holds only memchr 2.8.3 after its failed performance gate", async () => { + const config = await readFile(DEPENDABOT_CONFIG_URL, "utf8"); + + assert.match( + config, + /# memchr 2\.8\.3 regressed the performance gate; retry with the next release\.\n\s+- dependency-name: memchr\n\s+versions: \["2\.8\.3"\]/, + ); + }); }); describe("Checkout credential policy", () => { diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 56e70fe..cd57073 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -107,8 +107,7 @@ jobs: - name: Build JS benchmark packages if: matrix.kind == 'node' run: | - corepack pnpm --filter @srcmap/codec build - corepack pnpm --filter @srcmap/sourcemap build + corepack pnpm run build:test-artifacts:napi corepack pnpm --filter @srcmap/sourcemap-wasm build - name: Download real-world fixtures diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 2bb3a42..e334a70 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -58,9 +58,7 @@ jobs: # Build NAPI packages for JS tests - name: Build NAPI packages - run: | - corepack pnpm --filter @srcmap/codec build - corepack pnpm --filter @srcmap/sourcemap build + run: corepack pnpm run build:test-artifacts:napi # Build WASM packages for JS tests - name: Build WASM packages diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e41d8fe..3b9ef1d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,8 +71,8 @@ The experimental `generator`, `remapping` NAPI, and `scopes-wasm` binding crates cargo build # Debug build cargo build --release # Optimized build -# Build a specific NAPI package -corepack pnpm --filter @srcmap/sourcemap build +# Build NAPI test artifacts without rewriting tracked loaders +corepack pnpm run build:test-artifacts:napi # Build a specific WASM package for Node.js and browsers corepack pnpm --filter @srcmap/sourcemap-wasm build:all diff --git a/README.md b/README.md index e7c783c..59af0be 100644 --- a/README.md +++ b/README.md @@ -313,8 +313,7 @@ corepack pnpm --filter @srcmap/remapping-wasm build:all corepack pnpm --filter @srcmap/symbolicate-wasm build:all # NAPI packages -corepack pnpm --filter @srcmap/sourcemap build -corepack pnpm --filter @srcmap/codec build +corepack pnpm run build:test-artifacts:napi # JS benchmarks corepack pnpm --dir benchmarks run download-fixtures diff --git a/docs/superpowers/plans/2026-07-14-fetch-fixture-test-hardening.md b/docs/superpowers/plans/2026-07-14-fetch-fixture-test-hardening.md deleted file mode 100644 index 6646f2d..0000000 --- a/docs/superpowers/plans/2026-07-14-fetch-fixture-test-hardening.md +++ /dev/null @@ -1,148 +0,0 @@ -# Fetch Fixture Test Hardening 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:** Replace the scheduler-sensitive HTTP fixture regression test with deterministic staged input and correct the prior plan's expected file scope. - -**Architecture:** Keep `read_request` responsible for the `TcpStream` timeout and delegate header consumption to a helper generic over `Read`. Exercise that helper with a staged reader that signals and blocks exactly when more bytes are requested after the request line. - -**Tech Stack:** Rust 2024, standard library I/O and channels, Cargo integration tests, pnpm repository scripts. - -## Global Constraints - -- Preserve the existing 32 KiB request-header bound and two-second socket timeout. -- Add no dependencies. -- Keep production HTTP fixture behavior unchanged. -- Use signed conventional commits without attribution. - ---- - -### Task 1: Deterministic complete-header regression test - -**Files:** -- Modify: `crates/cli/tests/cli.rs:1-10,955-999` - -**Interfaces:** -- Consumes: `std::io::Read`, `std::sync::mpsc`, and the existing `MAX_REQUEST_HEADERS_SIZE` constant. -- Produces: `read_request_from(reader: &mut R) -> String` and a staged-reader regression test. - -- [ ] **Step 1: Extract the reader-generic helper without changing behavior** - -Keep socket configuration in `read_request` and move the existing complete-header loop and path extraction into: - -```rust -fn read_request(stream: &mut TcpStream) -> String { - stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap(); - read_request_from(stream) -} - -fn read_request_from(reader: &mut R) -> String { - let mut request = Vec::with_capacity(512); - while !request.ends_with(b"\r\n\r\n") { - let mut byte = [0_u8; 1]; - reader.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 2: Add a staged `Read` implementation and replace the timeout-based test** - -Use `Cursor>` for the two stages. On the first read after the request line is exhausted, signal the test and wait for explicit release before exposing the remaining headers: - -```rust -struct StagedRequest { - request_line: Cursor>, - headers: Cursor>, - waiting_sender: Option>, - release_receiver: Receiver<()>, -} - -impl Read for StagedRequest { - fn read(&mut self, buffer: &mut [u8]) -> std::io::Result { - let read = self.request_line.read(buffer)?; - if read > 0 { - return Ok(read); - } - - if let Some(sender) = self.waiting_sender.take() { - sender.send(()).map_err(std::io::Error::other)?; - self.release_receiver.recv().map_err(std::io::Error::other)?; - } - - self.headers.read(buffer) - } -} -``` - -Spawn `read_request_from` on a worker thread. Wait for the staged reader's signal, assert `path_receiver.try_recv()` returns `mpsc::TryRecvError::Empty`, release the remaining headers, and assert the parsed path is `/complete`. - -- [ ] **Step 3: Prove the regression test detects request-line-only behavior** - -Temporarily change the helper loop terminator to stop after the first newline. Run: - -```bash -cargo test -p srcmap-cli --test cli read_request_waits_for_complete_headers -- --exact -``` - -Expected: FAIL because the worker returns before the staged reader requests the remaining headers. Restore complete-header reading immediately afterward. - -- [ ] **Step 4: Verify the focused behavior** - -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: both commands exit successfully. - -### Task 2: Documentation scope and repository verification - -**Files:** -- Modify: `docs/superpowers/plans/2026-07-14-js-dependencies-fetch-fixture.md:217` - -**Interfaces:** -- Consumes: the merged file list from PR #75. -- Produces: an accurate expected-scope statement naming the intentional worktree ignore entry. - -- [ ] **Step 1: Correct the expected final scope** - -Replace the stale sentence with: - -```markdown -Expected: only the design, plan, fixture test helper, dependency manifests, lockfiles, and the intentional `.worktrees/` ignore entry are changed; commits have valid signatures. -``` - -- [ ] **Step 2: Run full verification with bounded logs** - -Run: - -```bash -pnpm check > /tmp/srcmap-fetch-hardening-check.log 2>&1 -pnpm test > /tmp/srcmap-fetch-hardening-test.log 2>&1 -git diff --check origin/main...HEAD -``` - -Expected: all commands exit successfully. - -- [ ] **Step 3: Review and commit the intended scope** - -Review `git status --short`, `git diff`, and staged files. Commit the test and documentation changes with: - -```bash -git commit -S -m "test: harden fetch fixture synchronization" -``` - -- [ ] **Step 4: Push and create the pull request** - -Push `codex/harden-fetch-fixture-test`, create a ready pull request targeting `main`, require all checks, and verify the exact merge commit after merging. diff --git a/docs/superpowers/plans/2026-07-14-js-dependencies-fetch-fixture.md b/docs/superpowers/plans/2026-07-14-js-dependencies-fetch-fixture.md deleted file mode 100644 index 8b42899..0000000 --- a/docs/superpowers/plans/2026-07-14-js-dependencies-fetch-fixture.md +++ /dev/null @@ -1,240 +0,0 @@ -# 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 manifests, lockfiles, and the intentional `.worktrees/` ignore entry 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. diff --git a/docs/superpowers/plans/2026-07-14-test-artifact-bootstrap.md b/docs/superpowers/plans/2026-07-14-test-artifact-bootstrap.md deleted file mode 100644 index e994d0a..0000000 --- a/docs/superpowers/plans/2026-07-14-test-artifact-bootstrap.md +++ /dev/null @@ -1,184 +0,0 @@ -# Test Artifact Bootstrap 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:** Add one root command that safely builds every generated NAPI and WASM artifact required by JavaScript tests in a clean checkout or worktree. - -**Architecture:** Define the build contract in root package scripts, use `--no-js` for NAPI builds to preserve tracked loaders, and reuse the command in the JavaScript runtime CI job. Lock the contract with the existing workflow policy test and document it in the contributor quick start. - -**Tech Stack:** pnpm 10, Node.js test runner, NAPI-RS CLI, wasm-pack, GitHub Actions. - -## Global Constraints - -- Add no dependencies. -- Preserve tracked NAPI JavaScript loaders. -- Do not make `pnpm test` rebuild artifacts automatically. -- Keep the existing focused package build commands available. -- Use signed conventional commits without attribution. - ---- - -### Task 1: Define the bootstrap contract test-first - -**Files:** -- Modify: `.github/scripts/workflow-policy.test.mjs` -- Modify: `package.json` -- Modify: `.github/workflows/ci.yml` - -**Interfaces:** -- Consumes: root `package.json` scripts and the `js-runtime` workflow job. -- Produces: `build:test-artifacts`, `build:test-artifacts:napi`, and `build:test-artifacts:wasm` package scripts used by contributors and CI. - -- [ ] **Step 1: Write the failing policy test** - -Add `PACKAGE_JSON_URL` and extend `Generated artifact policy` with a test that checks the exact root scripts and CI step: - -```js -const PACKAGE_JSON_URL = new URL("package.json", ROOT_URL); - -it("uses one safe bootstrap command for JavaScript test artifacts", async () => { - const packageJson = JSON.parse(await readFile(PACKAGE_JSON_URL, "utf8")); - assert.equal( - packageJson.scripts["build:test-artifacts"], - "pnpm run build:test-artifacts:napi && pnpm run build:test-artifacts:wasm", - ); - assert.equal( - packageJson.scripts["build:test-artifacts:napi"], - "pnpm --filter @srcmap/codec exec napi build --release --platform --no-js --dts ../../target/napi-codec.d.ts && pnpm --filter @srcmap/sourcemap exec napi build --release --platform --no-js --dts ../../target/napi-sourcemap.d.ts", - ); - assert.equal( - packageJson.scripts["build:test-artifacts:wasm"], - "pnpm --filter @srcmap/sourcemap-wasm build:all && pnpm --filter @srcmap/generator-wasm build:all && pnpm --filter @srcmap/remapping-wasm build:all && pnpm --filter @srcmap/symbolicate-wasm build:all", - ); - - const workflow = await readFile(CI_WORKFLOW_URL, "utf8"); - const job = workflowJob(workflow, "js-runtime"); - assert.match( - job, - / - name: Build JavaScript test artifacts\n run: corepack pnpm run build:test-artifacts/, - ); - assert.doesNotMatch(job, /corepack pnpm --filter @srcmap\/.+ build/); -}); -``` - -- [ ] **Step 2: Run the policy test and verify red** - -Run: - -```bash -node --test .github/scripts/workflow-policy.test.mjs -``` - -Expected: FAIL because `build:test-artifacts` is not defined. - -- [ ] **Step 3: Add the root package scripts** - -Add these scripts before `check:napi-declarations` in `package.json`: - -```json -"build:test-artifacts": "pnpm run build:test-artifacts:napi && pnpm run build:test-artifacts:wasm", -"build:test-artifacts:napi": "pnpm --filter @srcmap/codec exec napi build --release --platform --no-js --dts ../../target/napi-codec.d.ts && pnpm --filter @srcmap/sourcemap exec napi build --release --platform --no-js --dts ../../target/napi-sourcemap.d.ts", -"build:test-artifacts:wasm": "pnpm --filter @srcmap/sourcemap-wasm build:all && pnpm --filter @srcmap/generator-wasm build:all && pnpm --filter @srcmap/remapping-wasm build:all && pnpm --filter @srcmap/symbolicate-wasm build:all" -``` - -- [ ] **Step 4: Make CI use the root command** - -Replace the `Build N-API packages` and `Build WASM packages` steps in the `js-runtime` job with: - -```yaml - - name: Build JavaScript test artifacts - run: corepack pnpm run build:test-artifacts - - name: Check N-API declarations - run: node .github/scripts/check-napi-declarations.mjs -``` - -- [ ] **Step 5: Run the policy test and verify green** - -Run: - -```bash -node --test .github/scripts/workflow-policy.test.mjs -``` - -Expected: PASS. - -### Task 2: Document and prove clean-worktree setup - -**Files:** -- Modify: `CONTRIBUTING.md:15-38,77-96` - -**Interfaces:** -- Consumes: `pnpm build:test-artifacts` from Task 1. -- Produces: one contributor-facing setup command and explicit JavaScript test prerequisite. - -- [ ] **Step 1: Replace duplicated quick-start build commands** - -Keep the Rust workspace build, then replace the package-specific NAPI and WASM command block with: - -```bash -# Build all generated NAPI and WASM artifacts used by the JavaScript tests -corepack pnpm run build:test-artifacts -``` - -- [ ] **Step 2: Update the JavaScript testing note** - -Use: - -```bash -corepack pnpm run test:js # JS/WASM tests (run build:test-artifacts first) -``` - -- [ ] **Step 3: Install clean-worktree dependencies** - -Run: - -```bash -corepack pnpm install --ignore-scripts --frozen-lockfile -``` - -Expected: the lockfile is unchanged and no generated binding artifacts exist before bootstrap. - -- [ ] **Step 4: Execute the bootstrap command** - -Run with bounded output: - -```bash -corepack pnpm run build:test-artifacts > /tmp/srcmap-test-artifacts-build.log 2>&1 -``` - -Expected: the command exits successfully, both platform NAPI binaries exist, and every listed WASM package has Node and browser outputs. - -- [ ] **Step 5: Verify tracked loader hygiene** - -Run: - -```bash -git status --short -git diff -- packages/codec/index.js packages/sourcemap/index.js -``` - -Expected: only the intended policy, package, workflow, and contributor documentation files are modified; tracked loader files are unchanged. - -- [ ] **Step 6: Run full verification** - -Run with bounded logs: - -```bash -pnpm check > /tmp/srcmap-test-artifacts-check.log 2>&1 -pnpm test > /tmp/srcmap-test-artifacts-test.log 2>&1 -git diff --check -``` - -Expected: all commands exit successfully. - -- [ ] **Step 7: Review and commit** - -Review `git status --short`, the complete diff, and staged scope. Commit with: - -```bash -git commit -S -m "build: add test artifact bootstrap" -``` - -- [ ] **Step 8: Publish and verify** - -Push `codex/test-artifact-bootstrap`, create a ready pull request targeting `main`, require all checks, squash merge with a conventional subject, and verify CI, coverage, benchmarks, and Release Drafter on the exact merge commit. diff --git a/docs/superpowers/specs/2026-07-14-fetch-fixture-test-hardening-design.md b/docs/superpowers/specs/2026-07-14-fetch-fixture-test-hardening-design.md deleted file mode 100644 index d035d62..0000000 --- a/docs/superpowers/specs/2026-07-14-fetch-fixture-test-hardening-design.md +++ /dev/null @@ -1,21 +0,0 @@ -# Fetch Fixture Test Hardening Design - -## Goal - -Make the regression test for complete HTTP request header consumption deterministic, and correct the implementation plan so its expected diff matches the work that was merged. - -## Design - -Keep the production `TcpStream` wrapper responsible for configuring its read timeout. Extract the bounded request-header reading and path parsing into a helper generic over `Read`. - -Test the helper with a staged reader. The reader provides the request line, signals when the helper requests more input, blocks until the test releases the remaining headers, and then provides the header terminator. The test can use channel state instead of elapsed time to prove that parsing does not complete after the request line alone. - -The existing real TCP fetch tests continue to exercise the wrapper and network behavior. The new unit-level regression test isolates only the synchronization-sensitive header consumption contract. - -## Documentation - -Update the existing implementation plan's expected final scope to include the intentional `.gitignore` change for `.worktrees/`. - -## Verification - -Prove the regression test by temporarily restoring request-line-only behavior and observing the focused test fail, then restore complete-header reading and observe it pass. Run the focused CLI fetch tests, the full repository quality gate, and the full test suite before publishing the change. diff --git a/docs/superpowers/specs/2026-07-14-js-dependencies-fetch-fixture-design.md b/docs/superpowers/specs/2026-07-14-js-dependencies-fetch-fixture-design.md deleted file mode 100644 index b9add18..0000000 --- a/docs/superpowers/specs/2026-07-14-js-dependencies-fetch-fixture-design.md +++ /dev/null @@ -1,61 +0,0 @@ -# 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. diff --git a/docs/superpowers/specs/2026-07-14-test-artifact-bootstrap-design.md b/docs/superpowers/specs/2026-07-14-test-artifact-bootstrap-design.md deleted file mode 100644 index 86cc3f8..0000000 --- a/docs/superpowers/specs/2026-07-14-test-artifact-bootstrap-design.md +++ /dev/null @@ -1,28 +0,0 @@ -# Test Artifact Bootstrap Design - -## Goal - -Provide one repository command that prepares every generated NAPI and WASM artifact required by the JavaScript test suite in a clean checkout or isolated worktree. - -## Command contract - -Add `pnpm build:test-artifacts` at the workspace root. It runs two internal scripts in sequence: - -- `build:test-artifacts:napi` builds the codec and sourcemap NAPI binaries with `--no-js`, preserving the tracked JavaScript loaders while still generating the platform binary and declaration outputs. -- `build:test-artifacts:wasm` runs the existing `build:all` scripts for sourcemap, generator, remapping, and symbolicate WASM packages. - -The command requires the existing project prerequisites, including `wasm-pack`. It stops on the first failed build and does not install dependencies or run tests implicitly. - -## CI ownership - -Replace the duplicated NAPI and WASM build commands in the JavaScript runtime workflow with `corepack pnpm run build:test-artifacts`. CI then validates the same public command contributors use locally. Keep the declaration check after the bootstrap command and before the JavaScript tests. - -Extend the workflow policy test to require this root command in the JavaScript runtime job and reject reintroduced package-specific build commands in that job. - -## Documentation - -Update `CONTRIBUTING.md` so quick start uses the single bootstrap command. Keep the existing focused package build examples for contributors working on one binding package. Update the JavaScript testing note to name the bootstrap command explicitly. - -## Verification - -Use a clean isolated worktree with dependencies installed but no ignored binding artifacts. Run `pnpm build:test-artifacts`, confirm all required NAPI and WASM outputs exist, and confirm tracked loaders remain unchanged. Then run the workflow policy test, JavaScript tests, the full quality gate, and the full repository test suite.