From 0de11d9da80c5480163b6c3702221dbdb75697b4 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 05:22:35 -0500 Subject: [PATCH 1/9] test: split routine and slow assurance lanes --- .github/workflows/build-test.yml | 14 ++- AGENTS.md | 7 +- CLAUDE.md | 9 +- README.md | 28 +++-- docs/agents/runs/cleanup-1-9-ledger.md | 13 +- docs/agents/runs/issue-137-review-packet.md | 43 +++++++ docs/agents/runs/issue-137-session.md | 80 ++++++++++++ package.json | 16 ++- scripts/run-test-lane.js | 46 +++++++ scripts/test-lanes.js | 69 +++++++++++ tests/README.md | 11 +- tests/nip46/input-validation.test.ts | 129 ++++++++------------ tests/scripts/test-lanes.test.ts | 90 ++++++++++++++ 13 files changed, 440 insertions(+), 115 deletions(-) create mode 100644 docs/agents/runs/issue-137-review-packet.md create mode 100644 docs/agents/runs/issue-137-session.md create mode 100644 scripts/run-test-lane.js create mode 100644 scripts/test-lanes.js create mode 100644 tests/scripts/test-lanes.test.ts diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 47f86431..7c5d7390 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -104,12 +104,15 @@ jobs: - name: Lint run: npm run lint - - name: Run tests + - name: Run routine tests run: npm test + + - name: Run slow security and performance tests + run: npm run test:slow - - name: Run test coverage + - name: Run complete test coverage if: matrix.node-version == '20.x' - run: npm run test:coverage + run: npm run test:coverage:all - name: Build library run: npm run build @@ -153,9 +156,12 @@ jobs: - name: Lint run: bun run lint - - name: Run Bun tests + - name: Run Bun routine tests run: bun run test:bun + - name: Run Bun slow security and performance tests + run: bun run test:bun:slow + - name: Build library run: bun run build diff --git a/AGENTS.md b/AGENTS.md index 92d15736..e98e9c90 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,7 +14,8 @@ - `npm ci` — install the canonical dependency graph from `package-lock.json`. - `npm run package-manager:verify` — verify npm/Bun metadata, lockfiles, and CI policy. - `npm run build` — clean and compile TypeScript to `dist/`. -- `npm test` | `npm run test:watch` | `npm run test:coverage` — run Jest, watch mode, or coverage (reports in `coverage/`). +- `npm test` | `npm run test:watch` | `npm run test:coverage` — run the routine Jest lane, routine watch mode, or routine coverage. +- `npm run test:slow` | `npm run test:all` | `npm run test:coverage:all` — run the named security/performance lane or the complete test/coverage inventory. - `npm run lint` — ESLint (`@typescript-eslint`) over `.ts` sources. - `npm run format` — Prettier 3 for `src/`, `tests/`, `examples/`. - `npm run example` (or `example:*`) | `npm start` — run examples; default is the NIP‑07 example. @@ -31,14 +32,14 @@ - Framework: Jest with `ts-jest`, Node environment. - Naming: `*.test.ts` or `*.spec.ts`; mirror the `src/` layout. -- Coverage: keep or improve; use `npm run test:coverage`. +- Coverage: keep or improve; use `npm run test:coverage:all` before review so slow-lane files remain covered. - Use test vectors and the ephemeral relay; never include real credentials. ## Commit & Pull Request Guidelines - Commits: Conventional Commits (`feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`), imperative and concise. - Branches: create from `staging` using `feature/` or `fix/`; PRs target `staging`. -- PR checklist: clear what/why, linked issues (e.g., `#123`), tests and examples updated if behavior changes. Run `npm run lint && npm test && npm run build` before opening. +- PR checklist: clear what/why, linked issues (e.g., `#123`), tests and examples updated if behavior changes. Run `npm run lint && npm run test:all && npm run build` before opening. ## Security & Configuration Tips diff --git a/CLAUDE.md b/CLAUDE.md index f084d23a..ef5dfabb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -32,9 +32,12 @@ npm run format # Format code with Prettier ### Testing ```bash -npm test # Run all tests -npm run test:watch # Run tests in watch mode -npm run test:coverage # Generate coverage report +npm test # Run the routine feedback lane +npm run test:slow # Run security/performance load tests +npm run test:all # Run the complete routine + slow inventory +npm run test:watch # Run routine tests in watch mode +npm run test:coverage # Generate routine coverage +npm run test:coverage:all # Generate complete coverage for review/CI npm run test:nip01 # Test core NIP-01 functionality npm run test:nip04 # Test specific NIP (replace 04 with any NIP number) npm run test:crypto # Test all crypto functionality diff --git a/README.md b/README.md index 8ef2bff4..ad1a1084 100644 --- a/README.md +++ b/README.md @@ -442,7 +442,7 @@ Runnable examples cover core usage, NIP-specific flows, and curated groups. See ## Testing -The Jest suite uses an ephemeral relay where possible so normal test runs avoid external services. See the [testing guide](./tests/README.md) for organization and methodology, and use the [Command Reference](#command-reference) for every supported test command. +The Jest suite uses an ephemeral relay where possible so normal test runs avoid external services. `npm test` is the fast routine lane; `npm run test:slow` contains the explicitly named security/performance load suites, and `npm run test:all` runs the complete assurance set. CI always runs both lanes for Node and Bun. See the [testing guide](./tests/README.md) for organization and methodology, and use the [Command Reference](#command-reference) for every supported test command. ## Command Reference @@ -470,19 +470,23 @@ The `scripts` object in [package.json](./package.json) is the executable source ### Primary Tests -| Command | Definition | -| -------------------------- | -------------------------------- | -| `npm run test` | `jest` | -| `npm run test:watch` | `jest --watch` | -| `npm run test:coverage` | `jest --coverage` | -| `npm run test:integration` | `jest tests/integration.test.ts` | +| Command | Definition | +| ------------------------------ | -------------------------------------------------------------- | +| `npm run test` | `node scripts/run-test-lane.js jest routine` | +| `npm run test:watch` | `node scripts/run-test-lane.js jest routine --watch` | +| `npm run test:coverage` | `node scripts/run-test-lane.js jest routine --coverage` | +| `npm run test:coverage:all` | `node scripts/run-test-lane.js jest all --coverage` | +| `npm run test:slow` | `node scripts/run-test-lane.js jest slow` | +| `npm run test:integration` | `jest tests/integration.test.ts` | ### Bun Tests -| Command | Definition | -| ------------------------ | -------------------------------------------------------------- | -| `npm run test:bun` | `bun test ./tests --max-concurrency 1 --timeout 30000` | -| `npm run test:bun:watch` | `bun test ./tests --watch --max-concurrency 1 --timeout 30000` | +| Command | Definition | +| ------------------------ | ------------------------------------------------------ | +| `npm run test:bun` | `node scripts/run-test-lane.js bun routine` | +| `npm run test:bun:watch` | `node scripts/run-test-lane.js bun routine --watch` | +| `npm run test:bun:slow` | `node scripts/run-test-lane.js bun slow` | +| `npm run test:bun:all` | `bun run test:bun && bun run test:bun:slow` | ### NIP-01 and Core Tests @@ -534,7 +538,7 @@ The `scripts` object in [package.json](./package.json) is the executable source | Command | Definition | | ------------------------ | --------------------------------------------------------- | -| `npm run test:all` | `npm test` | +| `npm run test:all` | `npm test && npm run test:slow` | | `npm run test:crypto` | `jest tests/utils/crypto.test.ts tests/nip04 tests/nip44` | | `npm run test:identity` | `jest tests/nip05 tests/nip07 tests/nip19` | | `npm run test:protocols` | `jest tests/nip46 tests/nip47 tests/nip57` | diff --git a/docs/agents/runs/cleanup-1-9-ledger.md b/docs/agents/runs/cleanup-1-9-ledger.md index 595fe290..375b54a5 100644 --- a/docs/agents/runs/cleanup-1-9-ledger.md +++ b/docs/agents/runs/cleanup-1-9-ledger.md @@ -9,7 +9,7 @@ - Feature branches: one branch per approved ticket, created from the latest integrated `staging` - Human owner: plebdev - Started: 2026-07-18 -- Current status: items 1–5 / issues #131–#135 merged into `staging`; item 6 / issue #136 is fully green locally and awaits the final hosted rerun on PR #145 +- Current status: items 1–6 / issues #131–#136 merged into `staging`; item 7 / issue #137 is in implementation on `feature/fast-default-test-loop` - Skill setup status: present and verified (`AGENTS.md`, GitHub issue tracker, triage labels, domain docs, ADRs, CI, CodeRabbit) ## Goal @@ -25,9 +25,9 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch - Tickets: #131–#139 - Ticket sessions: created as each ticket starts - Agent briefs: Grok 4.5 is the exclusive delegated sidecar; Cursor exposes the highest available tier as `cursor-grok-4.5-high`, which is used for all standards/spec passes -- Review packets: `issue-131-review-packet.md` through `issue-136-review-packet.md`; created per later ticket +- Review packets: `issue-131-review-packet.md` through `issue-137-review-packet.md`; created per later ticket - Local CodeRabbit report: `issue-131-coderabbit-local.md` through `issue-136-coderabbit-local.md`; created per later ticket -- PR URL: #140 merged for issue #131; #141 merged for issue #132; #142 merged for issue #133; #143 merged for issue #134; #144 merged for issue #135; #145 open for issue #136; always non-draft and targeting `staging` +- PR URL: #140 merged for issue #131; #141 merged for issue #132; #142 merged for issue #133; #143 merged for issue #134; #144 merged for issue #135; #145 merged for issue #136; issue #137 PR pending; always non-draft and targeting `staging` ## Commands @@ -46,8 +46,8 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #133 shared diagnostic seam | AFK | merged | `feature/shared-diagnostics-completion` | Grok standards/spec pass; local and hosted clean | Jest/Bun 1067/1067; hosted CI green | | #134 NIP-47 service lifecycle | AFK | merged | `feature/nip47-service-lifecycle` | Grok pass; CodeRabbit local/hosted clean | Jest/Bun 1073/1073; hosted CI green | | #135 NIP-57 consolidation | AFK | merged | `feature/nip57-client-consolidation` | Grok pass; CodeRabbit local/hosted clean after fixes | Jest/Bun 1082/1082; hosted CI green | -| #136 NIP-46 protocol core | AFK | hosted rerun | `feature/nip46-protocol-core` | Grok/local clean; hosted findings fixed; rerun pending | Jest/Bun 1096/1096; prior CI green | -| #137 default test feedback loop | AFK | blocked by #136 | `feature/fast-default-test-loop` | pending | pending | +| #136 NIP-46 protocol core | AFK | merged | `feature/nip46-protocol-core` | Grok and CodeRabbit local/hosted clean after fixes | Jest/Bun 1096/1096; hosted CI green | +| #137 default test feedback loop | AFK | implementation | `feature/fast-default-test-loop` | Grok standards/spec pass; CodeRabbit pending | routine 1061; slow 40; full 1101 | | #138 public behavior test seams | AFK | blocked by #137 | `feature/public-behavior-test-seams` | pending | pending | | #139 ephemeral Relay internals | AFK | blocked by #138 | `feature/ephemeral-relay-internals` | pending | pending | @@ -66,7 +66,8 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #133 | `46d7289` | current Codex orchestrator; Grok 4.5 High reviewers | `b238461`, `6dd75c3`, `ae15ace` | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 204/204; Jest/Bun 1067/1067; all local gates and four hosted lanes green | | #134 | `2a3556d` | current Codex orchestrator; Grok 4.5 High reviewers | `569b266` plus review artifacts | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 6/6; Jest/Bun 1073/1073; all local gates and four hosted lanes green | | #135 | `25e055d` | current Codex orchestrator; Grok 4.5 High reviewers | `0909227`, `1b12872`, `b66d483` | Grok passes; CodeRabbit local/hosted clean after fixes | focused 23/23; NIP-57 41/41; Jest/Bun 1082/1082; all local gates and four hosted lanes green | -| #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | `cf3819b`, `baa2bf2`, `03a6652`, `7b5a7d0`, `2d4fc6f`, `d983bae`, `bc342cd`, `9e029be`, `1c38f2c` | Grok/local clean; hosted findings fixed; rerun pending | NIP-46 185/185; Jest/Bun 1096/1096; all local gates and prior hosted CI green | +| #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | PR #145 through merge `8b970e4` | Grok and CodeRabbit local/hosted clean after fixes | NIP-46 185/185; Jest/Bun 1096/1096; all local and hosted gates green | +| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | pending | Grok standards/spec passed; CodeRabbit pending | baseline 85/1096/58.793s; routine 84/1061/34.888s; slow 2/40/43.189s | ## Alignment Decisions diff --git a/docs/agents/runs/issue-137-review-packet.md b/docs/agents/runs/issue-137-review-packet.md new file mode 100644 index 00000000..a3b440bc --- /dev/null +++ b/docs/agents/runs/issue-137-review-packet.md @@ -0,0 +1,43 @@ +# Review Packet: #137 Default Test Feedback Loop + +## Issue + +- Issue: #137 +- Slice type: AFK test-infrastructure cleanup +- Acceptance criteria: reproducible timing evidence; deterministic removal of avoidable waits; materially faster routine lane; explicit slow security/performance lane; complete Node and Bun CI assurance +- Baseline: `8b970e4` +- Current diff: working branch against `8b970e4` + +## Implementation Summary + +The default Jest and Bun commands now run a canonical routine inventory, while two explicitly named security/performance load suites run in a slow lane. A small CommonJS lane module owns discovery and membership for Node 16 compatibility. CI runs routine and slow steps on Node 16, 18, 20, and Bun; Node 20 coverage uses the complete inventory. Parser-only NIP-46 validation cases no longer pay public-client teardown delays, cutting the conservative final default Jest wall time from 58.793s to 34.888s (40.7%); an earlier confirming run completed in 32.309s. + +## Implementation Evidence + +- `implement` session: `issue-137-session.md` +- `tdd` used: lane-contract test failed before the module and wiring existed +- Routine Jest: 84 suites / 1061 tests / 34.888s +- Slow Jest: 2 suites / 40 tests / 43.189s +- Routine Bun: 84 files / 1061 tests / 190.47s +- Slow Bun: 2 files / 40 tests / 40.38s +- Full union: 86 suites/files / 1101 tests in each runtime + +## Review Instructions + +Review only issue #137 unless a severe cross-slice regression appears. Verify that the lane inventory is canonical and complete; routine and slow sets are disjoint; targeted Jest paths still work; command forwarding and exit codes are preserved; CI runs both sets for every supported runtime; coverage includes all tests; input-validation changes retain public integration coverage while parser-only cases remain direct; and the before/after evidence is reproducible. + +## Reviewer Output + +```text +STANDARDS_STATUS: pass +STANDARDS_FINDINGS: +- P2 documentation command mismatch corrected in AGENTS.md and CLAUDE.md + +SPEC_STATUS: pass +SPEC_FINDINGS: +- none + +CODERABBIT_STATUS: pending +CODERABBIT_FINDINGS: +- pending +``` diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md new file mode 100644 index 00000000..4bb04de2 --- /dev/null +++ b/docs/agents/runs/issue-137-session.md @@ -0,0 +1,80 @@ +# Issue Session: #137 Default Test Feedback Loop + +## Issue + +- Issue: #137 +- Fixed point before session: `8b970e4` +- Worker session: current Codex orchestrator; Grok 4.5 High reviewers +- Commits: pending +- Status: implementation green; review and final gates pending + +## Inputs + +- Spec issue: #130 +- Ticket: #137 +- Relevant glossary terms: none; this slice changes test execution policy, not the domain model +- Relevant ADRs: none +- Prototype answer and source branch, if any: none + +## Baseline + +Reproducible command at `8b970e4`: + +```bash +npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json +``` + +- Default Jest: 85 suites, 1096 tests, 58.793 seconds. +- Slowest suites: `input-validation` 58.171s; NIP-46 `performance-security` 47.215s; `connection-failures` 32.528s; `permissions` 28.841s; `core-functionality` 25.902s; NIP-47 `nip44-encryption` 25.519s. + +## Implementation + +- Public interface used: `npm test`, `npm run test:slow`, `npm run test:all`, and matching Bun commands +- Behaviors covered: one canonical slow-lane inventory; complete disjoint routine/slow partition; targeted Jest invocation compatibility; explicit routine and slow CI steps on Node 16/18/20 and Bun; complete coverage on Node 20 +- `tdd` used: yes; `tests/scripts/test-lanes.test.ts` failed before the lane module and script/CI wiring existed, then passed after the runner was implemented +- Slow lane: only `tests/nip44/nip44-performance-security.test.ts` and `tests/nip46/performance-security.test.ts` +- Deterministic cleanup: parser-only NIP-46 input-validation cases now invoke `parseConnectionString` directly, and teardown disconnects only clients that successfully connected +- Compatibility: Jest routine selection uses a generated ignore pattern, preserving `npm test -- path/to/test` targeting; Bun receives an explicit routine file inventory + +## Timing Evidence + +| Lane | Suites | Tests | Time | +| --- | ---: | ---: | ---: | +| Baseline default Jest | 85 | 1096 | 58.793s | +| Routine Jest | 84 | 1061 | 34.888s | +| Slow Jest | 2 | 40 | 43.189s | +| Routine Bun | 84 | 1061 | 190.47s | +| Slow Bun | 2 | 40 | 40.38s | + +- The conservative final routine Jest run improved by 40.7%, exceeding the 40% target; an earlier confirming run completed in 32.309s. +- `input-validation` dropped from 58.171s in the baseline parallel run to 31.561s in the conservative final routine run; its isolated Jest run is 25.294s. +- Routine plus slow remains the complete 86-suite, 1101-test assurance set in both runtimes. + +## Review + +- Review fixed point: `8b970e4` +- Design findings: Grok selected a two-file named security/performance lane, required full CI union coverage, and identified parser validation as the largest deterministic low-hanging wait removal +- Standards findings: passed; the documentation command contract was corrected so complete coverage consistently names `test:coverage:all` +- Spec findings: passed with no P0/P1 findings +- Worthy fixes applied: aligned `AGENTS.md` and `CLAUDE.md` with the routine-versus-complete coverage contract +- Findings ignored with reasons: pending final review + +## Verification + +- Focused Jest/Bun input-validation: 33/33 in each runtime +- Lane contract: 5/5 +- Routine Jest: 84/84 suites, 1061/1061 tests +- Slow Jest: 2/2 suites, 40/40 tests +- Routine Bun: 84 files, 1061/1061 tests +- Slow Bun: 2 files, 40/40 tests +- Repository gates: command/package-manager policy, ESLint, strict TypeScript, build, examples, and pack pending final pass + +## Risks + +- `npm test` is now intentionally routine rather than complete; README and CI make `test:all` the explicit full assurance command. +- Focused NIP scripts remain unchanged and may include a slow file; this preserves existing contributor expectations. +- Slow membership is enforced by a tested canonical inventory so new files cannot silently become orphaned. + +| Issue | Why parked | Blocks | Required human action | Final PR decision | +| ----- | ---------- | ------ | --------------------- | ----------------- | +| None | — | — | — | — | diff --git a/package.json b/package.json index ed69e4c2..0db614f9 100644 --- a/package.json +++ b/package.json @@ -75,13 +75,17 @@ "lint": "eslint . --ext .ts", "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"examples/**/*.ts\"", "// Test Main": "-------------- Main Test Commands --------------", - "test": "jest", - "test:watch": "jest --watch", - "test:coverage": "jest --coverage", + "test": "node scripts/run-test-lane.js jest routine", + "test:watch": "node scripts/run-test-lane.js jest routine --watch", + "test:coverage": "node scripts/run-test-lane.js jest routine --coverage", + "test:coverage:all": "node scripts/run-test-lane.js jest all --coverage", + "test:slow": "node scripts/run-test-lane.js jest slow", "test:integration": "jest tests/integration.test.ts", "// Bun Migration": "-------------- Bun Test Migration --------------", - "test:bun": "bun test ./tests --max-concurrency 1 --timeout 30000", - "test:bun:watch": "bun test ./tests --watch --max-concurrency 1 --timeout 30000", + "test:bun": "node scripts/run-test-lane.js bun routine", + "test:bun:watch": "node scripts/run-test-lane.js bun routine --watch", + "test:bun:slow": "node scripts/run-test-lane.js bun slow", + "test:bun:all": "bun run test:bun && bun run test:bun:slow", "// Test Core": "-------------- Core Component Tests --------------", "test:nip01": "jest tests/nip01", "test:nip01:event": "jest tests/nip01/event", @@ -121,7 +125,7 @@ "test:nip70": "jest tests/nip70", "test:nip86": "jest tests/nip86", "// Test Groups": "-------------- Test Category Groups --------------", - "test:all": "npm test", + "test:all": "npm test && npm run test:slow", "test:crypto": "jest tests/utils/crypto.test.ts tests/nip04 tests/nip44", "test:identity": "jest tests/nip05 tests/nip07 tests/nip19", "test:protocols": "jest tests/nip46 tests/nip47 tests/nip57", diff --git a/scripts/run-test-lane.js b/scripts/run-test-lane.js new file mode 100644 index 00000000..7fc73308 --- /dev/null +++ b/scripts/run-test-lane.js @@ -0,0 +1,46 @@ +const path = require("path"); +const { spawnSync } = require("child_process"); +const { getJestArgsForLane, getTestFilesForLane } = require("./test-lanes"); + +const repoRoot = path.resolve(__dirname, ".."); +const [, , runtime, lane, ...extraArgs] = process.argv; + +function run(command, args) { + const result = spawnSync(command, args, { + cwd: repoRoot, + env: process.env, + stdio: "inherit", + }); + if (result.error) throw result.error; + process.exit(result.status === null ? 1 : result.status); +} + +function main() { + const testFiles = getTestFilesForLane(lane, repoRoot); + + if (runtime === "jest") { + const jestPackage = require.resolve("jest/package.json"); + const jestBinary = path.join(path.dirname(jestPackage), "bin", "jest.js"); + run(process.execPath, [ + jestBinary, + ...getJestArgsForLane(lane), + ...extraArgs, + ]); + } + + if (runtime === "bun") { + run("bun", [ + "test", + ...testFiles, + "--max-concurrency", + "1", + "--timeout", + "30000", + ...extraArgs, + ]); + } + + throw new Error(`Unknown test runtime: ${runtime}`); +} + +main(); diff --git a/scripts/test-lanes.js b/scripts/test-lanes.js new file mode 100644 index 00000000..91da0b21 --- /dev/null +++ b/scripts/test-lanes.js @@ -0,0 +1,69 @@ +const fs = require("fs"); +const path = require("path"); + +const SLOW_TEST_PATHS = Object.freeze([ + "tests/nip44/nip44-performance-security.test.ts", + "tests/nip46/performance-security.test.ts", +]); + +function toPosixPath(filePath) { + return filePath.split(path.sep).join("/"); +} + +function discoverTestFiles(repoRoot) { + const testsRoot = path.join(repoRoot, "tests"); + const files = []; + + function visit(directory) { + for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { + const absolutePath = path.join(directory, entry.name); + if (entry.isDirectory()) { + visit(absolutePath); + } else if (/\.test\.[cm]?[jt]sx?$/.test(entry.name)) { + files.push(toPosixPath(path.relative(repoRoot, absolutePath))); + } + } + } + + visit(testsRoot); + return files.sort(); +} + +function getTestFilesForLane(lane, repoRoot) { + const allFiles = discoverTestFiles(repoRoot); + const slowFiles = new Set(SLOW_TEST_PATHS); + const missingSlowFiles = SLOW_TEST_PATHS.filter( + (filePath) => !allFiles.includes(filePath), + ); + if (missingSlowFiles.length > 0) { + throw new Error( + `Slow test lane references missing files: ${missingSlowFiles.join(", ")}`, + ); + } + + if (lane === "all") return allFiles; + if (lane === "slow") return [...SLOW_TEST_PATHS]; + if (lane === "routine") { + return allFiles.filter((filePath) => !slowFiles.has(filePath)); + } + throw new Error(`Unknown test lane: ${lane}`); +} + +function getJestArgsForLane(lane) { + if (lane === "all") return []; + if (lane === "slow") return [...SLOW_TEST_PATHS]; + if (lane === "routine") { + const ignorePattern = SLOW_TEST_PATHS.map((filePath) => + filePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), + ).join("|"); + return [`--testPathIgnorePatterns=${ignorePattern}`]; + } + throw new Error(`Unknown test lane: ${lane}`); +} + +module.exports = { + SLOW_TEST_PATHS, + discoverTestFiles, + getJestArgsForLane, + getTestFilesForLane, +}; diff --git a/tests/README.md b/tests/README.md index b5631a6e..186e477b 100644 --- a/tests/README.md +++ b/tests/README.md @@ -66,16 +66,23 @@ Tests are organized into directories by NIP number, with subdirectories for spec ## Running Tests -To run all tests: +To run the routine feedback lane: ```bash npm test ``` -To run all tests with Bun: +To run the complete Jest assurance set, including the named slow security and performance lane: + +```bash +npm run test:all +``` + +To run the routine or complete assurance set with Bun: ```bash bun run test:bun +bun run test:bun:all ``` To run tests for a specific NIP: diff --git a/tests/nip46/input-validation.test.ts b/tests/nip46/input-validation.test.ts index 1af7c2ea..31315132 100644 --- a/tests/nip46/input-validation.test.ts +++ b/tests/nip46/input-validation.test.ts @@ -34,6 +34,13 @@ describe("NIP-46 Input Validation Security", () => { let client: SimpleNIP46Client; let bunker: SimpleNIP46Bunker; let userKeypair: { publicKey: string; privateKey: string }; + let clientConnected = false; + + async function connectClient(connectionString: string): Promise { + const userPubkey = await client.connect(connectionString); + clientConnected = true; + return userPubkey; + } beforeAll(async () => { relay = new NostrRelay(0); @@ -63,6 +70,7 @@ describe("NIP-46 Input Validation Security", () => { "sign_event", "nip44_encrypt", "nip44_decrypt", + "ping", ]); await bunker.start(); @@ -70,11 +78,12 @@ describe("NIP-46 Input Validation Security", () => { // and the subscription is active, so no additional waiting is needed client = new SimpleNIP46Client([relay.url], { timeout: 10000 }); // Increased timeout for full test suite + clientConnected = false; }); afterEach(async () => { try { - if (client) { + if (client && clientConnected) { await client.disconnect(); } } catch (e) { @@ -105,45 +114,40 @@ describe("NIP-46 Input Validation Security", () => { }); describe("Connection String Validation", () => { - test("rejects malformed connection strings", async () => { - await expect(client.connect("invalid-connection")).rejects.toThrow(); - await expect(client.connect("http://not-a-bunker")).rejects.toThrow(); - await expect(client.connect("")).rejects.toThrow(); - await expect(client.connect("bunker://")).rejects.toThrow(); + test("rejects malformed connection strings", () => { + expect(() => parseConnectionString("invalid-connection")).toThrow(); + expect(() => parseConnectionString("http://not-a-bunker")).toThrow(); + expect(() => parseConnectionString("")).toThrow(); + expect(() => parseConnectionString("bunker://")).toThrow(); }); - test("rejects connection strings with invalid pubkeys", async () => { - await expect( - client.connect("bunker://invalidpubkey?relay=ws://localhost:3334"), - ).rejects.toThrow(); + test("rejects connection strings with invalid pubkeys", () => { + expect(() => + parseConnectionString( + "bunker://invalidpubkey?relay=ws://localhost:3334", + ), + ).toThrow(); - await expect( - client.connect( + expect(() => + parseConnectionString( "bunker://gg" + "a".repeat(62) + "?relay=ws://localhost:3334", ), - ).rejects.toThrow(); + ).toThrow(); }); - test("validates relay URLs in connection strings", async () => { + test("validates relay URLs in connection strings", () => { const validPubkey = "a".repeat(64); - // Use timeout helper that properly cleans up timers - await expect( - raceWithTimeout( - client.connect(`bunker://${validPubkey}?relay=http://insecure.com`), - 2000, - "timeout", + expect(() => + parseConnectionString( + `bunker://${validPubkey}?relay=http://insecure.com`, ), - ).rejects.toThrow(); + ).toThrow(); - await expect( - raceWithTimeout( - client.connect(`bunker://${validPubkey}?relay=invalid-url`), - 2000, - "timeout", - ), - ).rejects.toThrow(); - }, 6000); // Reduced timeout + expect(() => + parseConnectionString(`bunker://${validPubkey}?relay=invalid-url`), + ).toThrow(); + }); test("validates connection string length", () => { const longString = "bunker://" + "a".repeat(8200); @@ -311,15 +315,14 @@ describe("NIP-46 Input Validation Security", () => { expect(connectionString).toMatch(/^bunker:\/\/[a-f0-9]{64}\?/); // Should be able to parse and connect - await client.connect(connectionString); + await connectClient(connectionString); const userPubkey = await client.getPublicKey(); expect(typeof userPubkey).toBe("string"); expect(userPubkey.length).toBe(64); - await client.disconnect(); }); - test("Invalid connection string formats", async () => { + test("Invalid connection string formats", () => { // Test various invalid formats const invalidStrings = [ "bunker://", @@ -331,7 +334,7 @@ describe("NIP-46 Input Validation Security", () => { ]; for (const invalidString of invalidStrings) { - await expect(client.connect(invalidString)).rejects.toThrow(); + expect(() => parseConnectionString(invalidString)).toThrow(); } }); @@ -359,7 +362,7 @@ describe("NIP-46 Input Validation Security", () => { }); describe("Key Validation", () => { - test("accepts hex keys with mixed case in connection strings", async () => { + test("accepts hex keys with mixed case in connection strings", () => { // Test various case combinations for public keys in connection strings const testKeys = [ "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", // lowercase @@ -368,43 +371,12 @@ describe("NIP-46 Input Validation Security", () => { ]; for (const pubkey of testKeys) { - // Test connection string parsing - this is where validation actually happens const connectionString = `bunker://${pubkey}?relay=${relay.url}`; - - // These should pass connection string parsing but fail during actual connection - // since the pubkeys don't match the bunker's actual key - try { - await client.connect(connectionString); - // If we reach here, the connection succeeded when it should have failed - // This is a security issue - mismatched signer keys should be rejected - throw new Error( - `Security violation: Connection with mismatched signer key ${pubkey} should have been rejected but succeeded`, - ); - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : String(error); - - // If it's our security violation error, re-throw to fail the test - if (errorMessage.startsWith("Security violation:")) { - throw error; - } - - // The key point is that it should NOT fail with the connection string parsing error - expect(errorMessage).not.toBe( - "Invalid signer public key in connection string", - ); - } finally { - // Always disconnect to prevent resource leaks and connection conflicts - try { - await client.disconnect(); - } catch (e) { - // Ignore cleanup errors - } - } + expect(parseConnectionString(connectionString).pubkey).toBe(pubkey); } }); - test("rejects invalid hex keys in connection strings", async () => { + test("rejects invalid hex keys in connection strings", () => { const invalidKeys = [ "G234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", // invalid character 'G' "1234567890abcdef123456789", // too short (25 chars) @@ -416,8 +388,7 @@ describe("NIP-46 Input Validation Security", () => { for (const pubkey of invalidKeys) { const connectionString = `bunker://${pubkey}?relay=${relay.url}`; - // These should throw during connection string parsing with the specific error message - await expect(client.connect(connectionString)).rejects.toThrow( + expect(() => parseConnectionString(connectionString)).toThrow( "Invalid signer public key in connection string", ); } @@ -427,7 +398,7 @@ describe("NIP-46 Input Validation Security", () => { describe("Event Content Validation", () => { test("handles events with various timestamps", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Current timestamp should always work const currentEvent = await client.signEvent({ @@ -452,7 +423,7 @@ describe("NIP-46 Input Validation Security", () => { test("handles events with various kind values", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Reduced test cases for speed const validKinds = [1, 1000]; // Reduced from [0, 1, 3, 1000, 10000] @@ -481,7 +452,7 @@ describe("NIP-46 Input Validation Security", () => { test("handles various content sizes", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Reduced content size for speed const normalContent = "Hello world! ".repeat(50); // Reduced from 100 @@ -517,7 +488,7 @@ describe("NIP-46 Input Validation Security", () => { test("validates event tag structure", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Valid tags should work const validEvent = await client.signEvent({ @@ -546,7 +517,7 @@ describe("NIP-46 Input Validation Security", () => { describe("Parameter Validation", () => { test("validates pubkey parameters", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Invalid pubkey format await expect( @@ -566,7 +537,7 @@ describe("NIP-46 Input Validation Security", () => { test("validates message size limits", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); const validPubkey = (await generateKeypair()).publicKey; @@ -590,7 +561,7 @@ describe("NIP-46 Input Validation Security", () => { test("sanitizes dangerous input", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); const validPubkey = (await generateKeypair()).publicKey; @@ -616,7 +587,7 @@ describe("NIP-46 Input Validation Security", () => { describe("Rate Limiting", () => { test("handles rapid requests gracefully", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Send multiple rapid requests const requests = Array(5) @@ -632,7 +603,7 @@ describe("NIP-46 Input Validation Security", () => { test("prevents DoS with large numbers of simultaneous requests", async () => { const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); // Reduced request count for speed const requests = Array(10) @@ -674,7 +645,7 @@ describe("NIP-46 Input Validation Security", () => { expect.assertions(3); // Ensure all assertions are executed const connectionString = bunker.getConnectionString(); - await client.connect(connectionString); + await connectClient(connectionString); try { // Force an encryption error diff --git a/tests/scripts/test-lanes.test.ts b/tests/scripts/test-lanes.test.ts new file mode 100644 index 00000000..ba9b7566 --- /dev/null +++ b/tests/scripts/test-lanes.test.ts @@ -0,0 +1,90 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ + +import { existsSync, readFileSync } from "fs"; +import path from "path"; + +type TestLane = "all" | "routine" | "slow"; + +interface TestLaneModule { + SLOW_TEST_PATHS: string[]; + discoverTestFiles(repoRoot: string): string[]; + getJestArgsForLane(lane: TestLane): string[]; + getTestFilesForLane(lane: TestLane, repoRoot: string): string[]; +} + +const repoRoot = path.resolve(__dirname, "../.."); +const lanes = require("../../scripts/test-lanes.js") as TestLaneModule; + +describe("test lane contract", () => { + const expectedSlowPaths = [ + "tests/nip44/nip44-performance-security.test.ts", + "tests/nip46/performance-security.test.ts", + ]; + + test("keeps one explicit sorted slow security and performance inventory", () => { + expect(lanes.SLOW_TEST_PATHS).toEqual(expectedSlowPaths); + for (const relativePath of lanes.SLOW_TEST_PATHS) { + expect(existsSync(path.join(repoRoot, relativePath))).toBe(true); + } + }); + + test("partitions every test file into exactly one routine or slow lane", () => { + const all = lanes.discoverTestFiles(repoRoot); + const routine = lanes.getTestFilesForLane("routine", repoRoot); + const slow = lanes.getTestFilesForLane("slow", repoRoot); + + expect(slow).toEqual(expectedSlowPaths); + expect(new Set([...routine, ...slow]).size).toBe(all.length); + expect([...routine, ...slow].sort()).toEqual(all); + expect(routine.filter((file) => slow.includes(file))).toEqual([]); + }); + + test("keeps targeted Jest runs compatible while excluding slow files by default", () => { + const routineArgs = lanes.getJestArgsForLane("routine"); + + expect(routineArgs).toHaveLength(1); + expect(routineArgs[0]).toContain("--testPathIgnorePatterns="); + for (const slowPath of expectedSlowPaths) { + expect(routineArgs[0]).toContain(slowPath.replace(/\./g, "\\.")); + } + expect(lanes.getJestArgsForLane("slow")).toEqual(expectedSlowPaths); + expect(lanes.getJestArgsForLane("all")).toEqual([]); + }); + + test("wires routine, slow, and complete Jest and Bun commands", () => { + const packageJson = JSON.parse( + readFileSync(path.join(repoRoot, "package.json"), "utf8"), + ) as { scripts: Record }; + + expect(packageJson.scripts.test).toBe( + "node scripts/run-test-lane.js jest routine", + ); + expect(packageJson.scripts["test:slow"]).toBe( + "node scripts/run-test-lane.js jest slow", + ); + expect(packageJson.scripts["test:all"]).toBe( + "npm test && npm run test:slow", + ); + expect(packageJson.scripts["test:bun"]).toBe( + "node scripts/run-test-lane.js bun routine", + ); + expect(packageJson.scripts["test:bun:slow"]).toBe( + "node scripts/run-test-lane.js bun slow", + ); + expect(packageJson.scripts["test:bun:all"]).toBe( + "bun run test:bun && bun run test:bun:slow", + ); + }); + + test("keeps complete assurance explicit in every hosted runtime", () => { + const workflow = readFileSync( + path.join(repoRoot, ".github/workflows/build-test.yml"), + "utf8", + ); + + expect(workflow).toContain("run: npm test"); + expect(workflow).toContain("run: npm run test:slow"); + expect(workflow).toContain("run: bun run test:bun"); + expect(workflow).toContain("run: bun run test:bun:slow"); + }); +}); From 91ffafaa3486614c64b64c613b418d4c9cc5bd1b Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 05:33:20 -0500 Subject: [PATCH 2/9] test: cover complete lane discovery contract --- docs/agents/runs/cleanup-1-9-ledger.md | 4 +-- docs/agents/runs/issue-137-review-packet.md | 14 ++++---- docs/agents/runs/issue-137-session.md | 24 +++++++------- scripts/test-lanes.js | 2 +- tests/scripts/test-lanes.test.ts | 36 ++++++++++++++++++++- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/docs/agents/runs/cleanup-1-9-ledger.md b/docs/agents/runs/cleanup-1-9-ledger.md index 375b54a5..c1d27080 100644 --- a/docs/agents/runs/cleanup-1-9-ledger.md +++ b/docs/agents/runs/cleanup-1-9-ledger.md @@ -47,7 +47,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 NIP-47 service lifecycle | AFK | merged | `feature/nip47-service-lifecycle` | Grok pass; CodeRabbit local/hosted clean | Jest/Bun 1073/1073; hosted CI green | | #135 NIP-57 consolidation | AFK | merged | `feature/nip57-client-consolidation` | Grok pass; CodeRabbit local/hosted clean after fixes | Jest/Bun 1082/1082; hosted CI green | | #136 NIP-46 protocol core | AFK | merged | `feature/nip46-protocol-core` | Grok and CodeRabbit local/hosted clean after fixes | Jest/Bun 1096/1096; hosted CI green | -| #137 default test feedback loop | AFK | implementation | `feature/fast-default-test-loop` | Grok standards/spec pass; CodeRabbit pending | routine 1061; slow 40; full 1101 | +| #137 default test feedback loop | AFK | review fixes | `feature/fast-default-test-loop` | Grok pass; CodeRabbit findings fixed, clean rerun pending | routine 1062; slow 40; full 1102 | | #138 public behavior test seams | AFK | blocked by #137 | `feature/public-behavior-test-seams` | pending | pending | | #139 ephemeral Relay internals | AFK | blocked by #138 | `feature/ephemeral-relay-internals` | pending | pending | @@ -67,7 +67,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 | `2a3556d` | current Codex orchestrator; Grok 4.5 High reviewers | `569b266` plus review artifacts | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 6/6; Jest/Bun 1073/1073; all local gates and four hosted lanes green | | #135 | `25e055d` | current Codex orchestrator; Grok 4.5 High reviewers | `0909227`, `1b12872`, `b66d483` | Grok passes; CodeRabbit local/hosted clean after fixes | focused 23/23; NIP-57 41/41; Jest/Bun 1082/1082; all local gates and four hosted lanes green | | #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | PR #145 through merge `8b970e4` | Grok and CodeRabbit local/hosted clean after fixes | NIP-46 185/185; Jest/Bun 1096/1096; all local and hosted gates green | -| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | pending | Grok standards/spec passed; CodeRabbit pending | baseline 85/1096/58.793s; routine 84/1061/34.888s; slow 2/40/43.189s | +| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`; review fix pending | Grok standards/spec passed; CodeRabbit findings fixed, clean rerun pending | baseline 85/1096/58.793s; routine 84/1062/32.391s; slow 2/40/43.189s | ## Alignment Decisions diff --git a/docs/agents/runs/issue-137-review-packet.md b/docs/agents/runs/issue-137-review-packet.md index a3b440bc..d716f75d 100644 --- a/docs/agents/runs/issue-137-review-packet.md +++ b/docs/agents/runs/issue-137-review-packet.md @@ -10,17 +10,17 @@ ## Implementation Summary -The default Jest and Bun commands now run a canonical routine inventory, while two explicitly named security/performance load suites run in a slow lane. A small CommonJS lane module owns discovery and membership for Node 16 compatibility. CI runs routine and slow steps on Node 16, 18, 20, and Bun; Node 20 coverage uses the complete inventory. Parser-only NIP-46 validation cases no longer pay public-client teardown delays, cutting the conservative final default Jest wall time from 58.793s to 34.888s (40.7%); an earlier confirming run completed in 32.309s. +The default Jest and Bun commands now run a canonical routine inventory, while two explicitly named security/performance load suites run in a slow lane. A small CommonJS lane module owns discovery and membership for Node 16 compatibility. CI runs routine and slow steps on Node 16, 18, 20, and Bun; Node 20 coverage uses the complete inventory. Parser-only NIP-46 validation cases no longer pay public-client teardown delays, cutting the post-review default Jest wall time from 58.793s to 32.391s (44.9%). ## Implementation Evidence - `implement` session: `issue-137-session.md` - `tdd` used: lane-contract test failed before the module and wiring existed -- Routine Jest: 84 suites / 1061 tests / 34.888s +- Routine Jest: 84 suites / 1062 tests / 32.391s - Slow Jest: 2 suites / 40 tests / 43.189s -- Routine Bun: 84 files / 1061 tests / 190.47s +- Routine Bun: 84 files / 1062 tests / 190.51s - Slow Bun: 2 files / 40 tests / 40.38s -- Full union: 86 suites/files / 1101 tests in each runtime +- Full union: 86 suites/files / 1102 tests in each runtime ## Review Instructions @@ -37,7 +37,9 @@ SPEC_STATUS: pass SPEC_FINDINGS: - none -CODERABBIT_STATUS: pending +CODERABBIT_STATUS: fixes applied; clean rerun pending CODERABBIT_FINDINGS: -- pending +- major: include Jest-compatible .spec.* files in canonical discovery — fixed with a red/green regression test +- minor: assert routine and complete coverage wiring — fixed +- minor: replace the ledger baseline hash with the implementation commit — fixed ``` diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index 4bb04de2..3ca1000e 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -5,8 +5,8 @@ - Issue: #137 - Fixed point before session: `8b970e4` - Worker session: current Codex orchestrator; Grok 4.5 High reviewers -- Commits: pending -- Status: implementation green; review and final gates pending +- Commits: `0de11d9`; review-fix commit pending +- Status: implementation and CodeRabbit fixes green; clean review rerun and final gates pending ## Inputs @@ -41,14 +41,14 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json | Lane | Suites | Tests | Time | | --- | ---: | ---: | ---: | | Baseline default Jest | 85 | 1096 | 58.793s | -| Routine Jest | 84 | 1061 | 34.888s | +| Routine Jest | 84 | 1062 | 32.391s | | Slow Jest | 2 | 40 | 43.189s | -| Routine Bun | 84 | 1061 | 190.47s | +| Routine Bun | 84 | 1062 | 190.51s | | Slow Bun | 2 | 40 | 40.38s | -- The conservative final routine Jest run improved by 40.7%, exceeding the 40% target; an earlier confirming run completed in 32.309s. -- `input-validation` dropped from 58.171s in the baseline parallel run to 31.561s in the conservative final routine run; its isolated Jest run is 25.294s. -- Routine plus slow remains the complete 86-suite, 1101-test assurance set in both runtimes. +- The post-review routine Jest run improved by 44.9%, exceeding the 40% target. +- `input-validation` dropped from 58.171s in the baseline parallel run to 29.015s in the post-review routine run; its isolated Jest run is 25.294s. +- Routine plus slow remains the complete 86-suite, 1102-test assurance set in both runtimes. ## Review @@ -56,16 +56,16 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Design findings: Grok selected a two-file named security/performance lane, required full CI union coverage, and identified parser validation as the largest deterministic low-hanging wait removal - Standards findings: passed; the documentation command contract was corrected so complete coverage consistently names `test:coverage:all` - Spec findings: passed with no P0/P1 findings -- Worthy fixes applied: aligned `AGENTS.md` and `CLAUDE.md` with the routine-versus-complete coverage contract -- Findings ignored with reasons: pending final review +- Worthy fixes applied: aligned `AGENTS.md` and `CLAUDE.md` with the routine-versus-complete coverage contract; expanded discovery to Jest-compatible `.spec.*` files; pinned routine and complete coverage wiring in tests; recorded the actual implementation commit in the ledger +- Findings ignored with reasons: none; all three local CodeRabbit findings were valid and fixed ## Verification - Focused Jest/Bun input-validation: 33/33 in each runtime -- Lane contract: 5/5 -- Routine Jest: 84/84 suites, 1061/1061 tests +- Lane contract: 6/6 in Jest and Bun +- Routine Jest: 84/84 suites, 1062/1062 tests - Slow Jest: 2/2 suites, 40/40 tests -- Routine Bun: 84 files, 1061/1061 tests +- Routine Bun: 84 files, 1062/1062 tests - Slow Bun: 2 files, 40/40 tests - Repository gates: command/package-manager policy, ESLint, strict TypeScript, build, examples, and pack pending final pass diff --git a/scripts/test-lanes.js b/scripts/test-lanes.js index 91da0b21..48f18462 100644 --- a/scripts/test-lanes.js +++ b/scripts/test-lanes.js @@ -19,7 +19,7 @@ function discoverTestFiles(repoRoot) { const absolutePath = path.join(directory, entry.name); if (entry.isDirectory()) { visit(absolutePath); - } else if (/\.test\.[cm]?[jt]sx?$/.test(entry.name)) { + } else if (/\.(?:test|spec)\.[cm]?[jt]sx?$/.test(entry.name)) { files.push(toPosixPath(path.relative(repoRoot, absolutePath))); } } diff --git a/tests/scripts/test-lanes.test.ts b/tests/scripts/test-lanes.test.ts index ba9b7566..eb0fc3b4 100644 --- a/tests/scripts/test-lanes.test.ts +++ b/tests/scripts/test-lanes.test.ts @@ -1,6 +1,14 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { existsSync, readFileSync } from "fs"; +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from "fs"; +import { tmpdir } from "os"; import path from "path"; type TestLane = "all" | "routine" | "slow"; @@ -39,6 +47,25 @@ describe("test lane contract", () => { expect(routine.filter((file) => slow.includes(file))).toEqual([]); }); + test("discovers both Jest test and spec filename conventions", () => { + const fixtureRoot = mkdtempSync(path.join(tmpdir(), "snstr-test-lanes-")); + const fixtureTests = path.join(fixtureRoot, "tests"); + + try { + mkdirSync(fixtureTests); + writeFileSync(path.join(fixtureTests, "alpha.test.ts"), ""); + writeFileSync(path.join(fixtureTests, "beta.spec.ts"), ""); + writeFileSync(path.join(fixtureTests, "not-a-test.ts"), ""); + + expect(lanes.discoverTestFiles(fixtureRoot)).toEqual([ + "tests/alpha.test.ts", + "tests/beta.spec.ts", + ]); + } finally { + rmSync(fixtureRoot, { force: true, recursive: true }); + } + }); + test("keeps targeted Jest runs compatible while excluding slow files by default", () => { const routineArgs = lanes.getJestArgsForLane("routine"); @@ -65,6 +92,12 @@ describe("test lane contract", () => { expect(packageJson.scripts["test:all"]).toBe( "npm test && npm run test:slow", ); + expect(packageJson.scripts["test:coverage"]).toBe( + "node scripts/run-test-lane.js jest routine --coverage", + ); + expect(packageJson.scripts["test:coverage:all"]).toBe( + "node scripts/run-test-lane.js jest all --coverage", + ); expect(packageJson.scripts["test:bun"]).toBe( "node scripts/run-test-lane.js bun routine", ); @@ -86,5 +119,6 @@ describe("test lane contract", () => { expect(workflow).toContain("run: npm run test:slow"); expect(workflow).toContain("run: bun run test:bun"); expect(workflow).toContain("run: bun run test:bun:slow"); + expect(workflow).toContain("run: npm run test:coverage:all"); }); }); From 45a1a4f27e3d4a9df974eefd18042141eecde232 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 05:40:48 -0500 Subject: [PATCH 3/9] docs: record fast test lane verification --- docs/agents/runs/cleanup-1-9-ledger.md | 4 ++-- docs/agents/runs/issue-137-review-packet.md | 9 +++++---- docs/agents/runs/issue-137-session.md | 13 ++++++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/agents/runs/cleanup-1-9-ledger.md b/docs/agents/runs/cleanup-1-9-ledger.md index c1d27080..2cf24375 100644 --- a/docs/agents/runs/cleanup-1-9-ledger.md +++ b/docs/agents/runs/cleanup-1-9-ledger.md @@ -47,7 +47,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 NIP-47 service lifecycle | AFK | merged | `feature/nip47-service-lifecycle` | Grok pass; CodeRabbit local/hosted clean | Jest/Bun 1073/1073; hosted CI green | | #135 NIP-57 consolidation | AFK | merged | `feature/nip57-client-consolidation` | Grok pass; CodeRabbit local/hosted clean after fixes | Jest/Bun 1082/1082; hosted CI green | | #136 NIP-46 protocol core | AFK | merged | `feature/nip46-protocol-core` | Grok and CodeRabbit local/hosted clean after fixes | Jest/Bun 1096/1096; hosted CI green | -| #137 default test feedback loop | AFK | review fixes | `feature/fast-default-test-loop` | Grok pass; CodeRabbit findings fixed, clean rerun pending | routine 1062; slow 40; full 1102 | +| #137 default test feedback loop | AFK | PR pending | `feature/fast-default-test-loop` | Grok pass; CodeRabbit local clean after fixes | routine 1062; slow 40; coverage 1102 | | #138 public behavior test seams | AFK | blocked by #137 | `feature/public-behavior-test-seams` | pending | pending | | #139 ephemeral Relay internals | AFK | blocked by #138 | `feature/ephemeral-relay-internals` | pending | pending | @@ -67,7 +67,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 | `2a3556d` | current Codex orchestrator; Grok 4.5 High reviewers | `569b266` plus review artifacts | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 6/6; Jest/Bun 1073/1073; all local gates and four hosted lanes green | | #135 | `25e055d` | current Codex orchestrator; Grok 4.5 High reviewers | `0909227`, `1b12872`, `b66d483` | Grok passes; CodeRabbit local/hosted clean after fixes | focused 23/23; NIP-57 41/41; Jest/Bun 1082/1082; all local gates and four hosted lanes green | | #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | PR #145 through merge `8b970e4` | Grok and CodeRabbit local/hosted clean after fixes | NIP-46 185/185; Jest/Bun 1096/1096; all local and hosted gates green | -| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`; review fix pending | Grok standards/spec passed; CodeRabbit findings fixed, clean rerun pending | baseline 85/1096/58.793s; routine 84/1062/32.391s; slow 2/40/43.189s | +| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`, `91ffafa` | Grok standards/spec passed; CodeRabbit local clean after fixes | baseline 85/1096/58.793s; routine 84/1062/32.391s; slow 2/40/43.640s; coverage 86/1102 green | ## Alignment Decisions diff --git a/docs/agents/runs/issue-137-review-packet.md b/docs/agents/runs/issue-137-review-packet.md index d716f75d..1700e15b 100644 --- a/docs/agents/runs/issue-137-review-packet.md +++ b/docs/agents/runs/issue-137-review-packet.md @@ -17,10 +17,11 @@ The default Jest and Bun commands now run a canonical routine inventory, while t - `implement` session: `issue-137-session.md` - `tdd` used: lane-contract test failed before the module and wiring existed - Routine Jest: 84 suites / 1062 tests / 32.391s -- Slow Jest: 2 suites / 40 tests / 43.189s +- Slow Jest: 2 suites / 40 tests / 43.640s - Routine Bun: 84 files / 1062 tests / 190.51s -- Slow Bun: 2 files / 40 tests / 40.38s +- Slow Bun: 2 files / 40 tests / 40.41s - Full union: 86 suites/files / 1102 tests in each runtime +- Complete Jest coverage command: 86 suites / 1102 tests / 53.732s; 80.53% statement coverage ## Review Instructions @@ -35,9 +36,9 @@ STANDARDS_FINDINGS: SPEC_STATUS: pass SPEC_FINDINGS: -- none +- none; post-CodeRabbit Grok follow-up also passed -CODERABBIT_STATUS: fixes applied; clean rerun pending +CODERABBIT_STATUS: pass after fixes; committed rerun returned zero findings CODERABBIT_FINDINGS: - major: include Jest-compatible .spec.* files in canonical discovery — fixed with a red/green regression test - minor: assert routine and complete coverage wiring — fixed diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index 3ca1000e..e5347f75 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -5,8 +5,8 @@ - Issue: #137 - Fixed point before session: `8b970e4` - Worker session: current Codex orchestrator; Grok 4.5 High reviewers -- Commits: `0de11d9`; review-fix commit pending -- Status: implementation and CodeRabbit fixes green; clean review rerun and final gates pending +- Commits: `0de11d9`, `91ffafa`; final review-record commit pending +- Status: implementation, local reviews, and final local gates green; PR pending ## Inputs @@ -42,9 +42,9 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json | --- | ---: | ---: | ---: | | Baseline default Jest | 85 | 1096 | 58.793s | | Routine Jest | 84 | 1062 | 32.391s | -| Slow Jest | 2 | 40 | 43.189s | +| Slow Jest | 2 | 40 | 43.640s | | Routine Bun | 84 | 1062 | 190.51s | -| Slow Bun | 2 | 40 | 40.38s | +| Slow Bun | 2 | 40 | 40.41s | - The post-review routine Jest run improved by 44.9%, exceeding the 40% target. - `input-validation` dropped from 58.171s in the baseline parallel run to 29.015s in the post-review routine run; its isolated Jest run is 25.294s. @@ -58,6 +58,8 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Spec findings: passed with no P0/P1 findings - Worthy fixes applied: aligned `AGENTS.md` and `CLAUDE.md` with the routine-versus-complete coverage contract; expanded discovery to Jest-compatible `.spec.*` files; pinned routine and complete coverage wiring in tests; recorded the actual implementation commit in the ledger - Findings ignored with reasons: none; all three local CodeRabbit findings were valid and fixed +- CodeRabbit result: clean committed rerun with zero findings after fixes +- Grok follow-up: standards and spec both passed after the CodeRabbit delta with no findings ## Verification @@ -67,7 +69,8 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Slow Jest: 2/2 suites, 40/40 tests - Routine Bun: 84 files, 1062/1062 tests - Slow Bun: 2 files, 40/40 tests -- Repository gates: command/package-manager policy, ESLint, strict TypeScript, build, examples, and pack pending final pass +- Complete coverage: 86/86 suites, 1102/1102 tests in 53.732s; 80.53% statements, 68.44% branches, 82.72% functions, 81.02% lines +- Repository gates: command/package-manager policy, ESLint, strict TypeScript, CommonJS script syntax, build, examples, pack, and diff integrity all green ## Risks From 295d1142a7cacc5f76b888cda6a258a17343e78e Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 05:55:41 -0500 Subject: [PATCH 4/9] test: keep Bun watch discovery dynamic --- docs/agents/runs/cleanup-1-9-ledger.md | 6 +-- docs/agents/runs/issue-137-review-packet.md | 16 ++++--- docs/agents/runs/issue-137-session.md | 19 +++++---- scripts/run-test-lane.js | 46 +++++++++++++++------ tests/README.md | 2 + tests/scripts/test-lanes.test.ts | 34 +++++++++++++++ 6 files changed, 92 insertions(+), 31 deletions(-) diff --git a/docs/agents/runs/cleanup-1-9-ledger.md b/docs/agents/runs/cleanup-1-9-ledger.md index 2cf24375..5b707f74 100644 --- a/docs/agents/runs/cleanup-1-9-ledger.md +++ b/docs/agents/runs/cleanup-1-9-ledger.md @@ -9,7 +9,7 @@ - Feature branches: one branch per approved ticket, created from the latest integrated `staging` - Human owner: plebdev - Started: 2026-07-18 -- Current status: items 1–6 / issues #131–#136 merged into `staging`; item 7 / issue #137 is in implementation on `feature/fast-default-test-loop` +- Current status: items 1–6 / issues #131–#136 merged into `staging`; item 7 / issue #137 is implemented with PR #146 pending on `feature/fast-default-test-loop` - Skill setup status: present and verified (`AGENTS.md`, GitHub issue tracker, triage labels, domain docs, ADRs, CI, CodeRabbit) ## Goal @@ -47,7 +47,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 NIP-47 service lifecycle | AFK | merged | `feature/nip47-service-lifecycle` | Grok pass; CodeRabbit local/hosted clean | Jest/Bun 1073/1073; hosted CI green | | #135 NIP-57 consolidation | AFK | merged | `feature/nip57-client-consolidation` | Grok pass; CodeRabbit local/hosted clean after fixes | Jest/Bun 1082/1082; hosted CI green | | #136 NIP-46 protocol core | AFK | merged | `feature/nip46-protocol-core` | Grok and CodeRabbit local/hosted clean after fixes | Jest/Bun 1096/1096; hosted CI green | -| #137 default test feedback loop | AFK | PR pending | `feature/fast-default-test-loop` | Grok pass; CodeRabbit local clean after fixes | routine 1062; slow 40; coverage 1102 | +| #137 default test feedback loop | AFK | PR fixes | `feature/fast-default-test-loop` | Grok pass; hosted CodeRabbit fixes in review | routine 1063; slow 40; full 1103 | | #138 public behavior test seams | AFK | blocked by #137 | `feature/public-behavior-test-seams` | pending | pending | | #139 ephemeral Relay internals | AFK | blocked by #138 | `feature/ephemeral-relay-internals` | pending | pending | @@ -67,7 +67,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 | `2a3556d` | current Codex orchestrator; Grok 4.5 High reviewers | `569b266` plus review artifacts | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 6/6; Jest/Bun 1073/1073; all local gates and four hosted lanes green | | #135 | `25e055d` | current Codex orchestrator; Grok 4.5 High reviewers | `0909227`, `1b12872`, `b66d483` | Grok passes; CodeRabbit local/hosted clean after fixes | focused 23/23; NIP-57 41/41; Jest/Bun 1082/1082; all local gates and four hosted lanes green | | #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | PR #145 through merge `8b970e4` | Grok and CodeRabbit local/hosted clean after fixes | NIP-46 185/185; Jest/Bun 1096/1096; all local and hosted gates green | -| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`, `91ffafa` | Grok standards/spec passed; CodeRabbit local clean after fixes | baseline 85/1096/58.793s; routine 84/1062/32.391s; slow 2/40/43.640s; coverage 86/1102 green | +| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`, `91ffafa`; hosted fix pending | Grok standards/spec passed; hosted CodeRabbit fixes pending clean rerun | baseline 85/1096/58.793s; routine 84/1063/32.356s; slow 2/40/43.640s; full 86/1103 | ## Alignment Decisions diff --git a/docs/agents/runs/issue-137-review-packet.md b/docs/agents/runs/issue-137-review-packet.md index 1700e15b..b40c2b91 100644 --- a/docs/agents/runs/issue-137-review-packet.md +++ b/docs/agents/runs/issue-137-review-packet.md @@ -10,18 +10,18 @@ ## Implementation Summary -The default Jest and Bun commands now run a canonical routine inventory, while two explicitly named security/performance load suites run in a slow lane. A small CommonJS lane module owns discovery and membership for Node 16 compatibility. CI runs routine and slow steps on Node 16, 18, 20, and Bun; Node 20 coverage uses the complete inventory. Parser-only NIP-46 validation cases no longer pay public-client teardown delays, cutting the post-review default Jest wall time from 58.793s to 32.391s (44.9%). +The default Jest and Bun commands now run a canonical routine inventory, while two explicitly named security/performance load suites run in a slow lane. A small CommonJS lane module owns discovery and membership for Node 16 compatibility. CI runs routine and slow steps on Node 16, 18, 20, and Bun; Node 20 coverage uses the complete inventory. Parser-only NIP-46 validation cases no longer pay public-client teardown delays, cutting the hosted-fix default Jest wall time from 58.793s to 32.356s (45.0%). ## Implementation Evidence - `implement` session: `issue-137-session.md` - `tdd` used: lane-contract test failed before the module and wiring existed -- Routine Jest: 84 suites / 1062 tests / 32.391s +- Routine Jest: 84 suites / 1063 tests / 32.356s - Slow Jest: 2 suites / 40 tests / 43.640s -- Routine Bun: 84 files / 1062 tests / 190.51s +- Routine Bun: 84 files / 1063 tests / 190.68s - Slow Bun: 2 files / 40 tests / 40.41s -- Full union: 86 suites/files / 1102 tests in each runtime -- Complete Jest coverage command: 86 suites / 1102 tests / 53.732s; 80.53% statement coverage +- Full union: 86 suites/files / 1103 tests in each runtime +- Complete Jest coverage command: pre-hosted-fix 86 suites / 1102 tests / 53.732s; final rerun pending ## Review Instructions @@ -38,9 +38,13 @@ SPEC_STATUS: pass SPEC_FINDINGS: - none; post-CodeRabbit Grok follow-up also passed -CODERABBIT_STATUS: pass after fixes; committed rerun returned zero findings +CODERABBIT_STATUS: local pass after fixes; hosted findings fixed, clean rerun pending CODERABBIT_FINDINGS: - major: include Jest-compatible .spec.* files in canonical discovery — fixed with a red/green regression test - minor: assert routine and complete coverage wiring — fixed - minor: replace the ledger baseline hash with the implementation commit — fixed +- hosted minor: synchronize the top-level run status — fixed +- hosted minor: dynamically discover new routine tests during Bun watch without admitting slow paths — fixed with a red/green pure argument-builder test +- hosted minor: document standalone Jest and Bun slow commands — fixed +- hosted major: directly cover spawned Bun argument construction for dynamic watch and fixed non-watch modes — fixed ``` diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index e5347f75..fba7437e 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -6,7 +6,7 @@ - Fixed point before session: `8b970e4` - Worker session: current Codex orchestrator; Grok 4.5 High reviewers - Commits: `0de11d9`, `91ffafa`; final review-record commit pending -- Status: implementation, local reviews, and final local gates green; PR pending +- Status: hosted CodeRabbit fixes in progress on PR #146 ## Inputs @@ -41,14 +41,14 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json | Lane | Suites | Tests | Time | | --- | ---: | ---: | ---: | | Baseline default Jest | 85 | 1096 | 58.793s | -| Routine Jest | 84 | 1062 | 32.391s | +| Routine Jest | 84 | 1063 | 32.356s | | Slow Jest | 2 | 40 | 43.640s | -| Routine Bun | 84 | 1062 | 190.51s | +| Routine Bun | 84 | 1063 | 190.68s | | Slow Bun | 2 | 40 | 40.41s | -- The post-review routine Jest run improved by 44.9%, exceeding the 40% target. +- The hosted-fix routine Jest run improved by 45.0%, exceeding the 40% target. - `input-validation` dropped from 58.171s in the baseline parallel run to 29.015s in the post-review routine run; its isolated Jest run is 25.294s. -- Routine plus slow remains the complete 86-suite, 1102-test assurance set in both runtimes. +- Routine plus slow remains the complete 86-suite, 1103-test assurance set in both runtimes. ## Review @@ -60,16 +60,17 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Findings ignored with reasons: none; all three local CodeRabbit findings were valid and fixed - CodeRabbit result: clean committed rerun with zero findings after fixes - Grok follow-up: standards and spec both passed after the CodeRabbit delta with no findings +- Hosted CodeRabbit findings: accepted all four; synchronized the run status, documented standalone slow commands, and made routine Bun watch discovery dynamic through a tested pure argument builder while preserving fixed non-watch inventory ## Verification - Focused Jest/Bun input-validation: 33/33 in each runtime -- Lane contract: 6/6 in Jest and Bun -- Routine Jest: 84/84 suites, 1062/1062 tests +- Lane contract: 7/7 in Jest and Bun +- Routine Jest: 84/84 suites, 1063/1063 tests - Slow Jest: 2/2 suites, 40/40 tests -- Routine Bun: 84 files, 1062/1062 tests +- Routine Bun: 84 files, 1063/1063 tests - Slow Bun: 2 files, 40/40 tests -- Complete coverage: 86/86 suites, 1102/1102 tests in 53.732s; 80.53% statements, 68.44% branches, 82.72% functions, 81.02% lines +- Complete coverage before the hosted-fix regression test: 86/86 suites, 1102/1102 tests in 53.732s; final rerun pending - Repository gates: command/package-manager policy, ESLint, strict TypeScript, CommonJS script syntax, build, examples, pack, and diff integrity all green ## Risks diff --git a/scripts/run-test-lane.js b/scripts/run-test-lane.js index 7fc73308..04384022 100644 --- a/scripts/run-test-lane.js +++ b/scripts/run-test-lane.js @@ -1,6 +1,10 @@ const path = require("path"); const { spawnSync } = require("child_process"); -const { getJestArgsForLane, getTestFilesForLane } = require("./test-lanes"); +const { + SLOW_TEST_PATHS, + getJestArgsForLane, + getTestFilesForLane, +} = require("./test-lanes"); const repoRoot = path.resolve(__dirname, ".."); const [, , runtime, lane, ...extraArgs] = process.argv; @@ -15,10 +19,32 @@ function run(command, args) { process.exit(result.status === null ? 1 : result.status); } -function main() { - const testFiles = getTestFilesForLane(lane, repoRoot); +function getBunArgsForLane(lane, extraArgs, root = repoRoot) { + const testFiles = getTestFilesForLane(lane, root); + const isRoutineWatch = lane === "routine" && extraArgs.includes("--watch"); + const testSelection = isRoutineWatch + ? [ + "./tests", + ...SLOW_TEST_PATHS.map( + (filePath) => `--path-ignore-patterns=${filePath}`, + ), + ] + : testFiles; + + return [ + "test", + ...testSelection, + "--max-concurrency", + "1", + "--timeout", + "30000", + ...extraArgs, + ]; +} +function main() { if (runtime === "jest") { + getTestFilesForLane(lane, repoRoot); const jestPackage = require.resolve("jest/package.json"); const jestBinary = path.join(path.dirname(jestPackage), "bin", "jest.js"); run(process.execPath, [ @@ -29,18 +55,12 @@ function main() { } if (runtime === "bun") { - run("bun", [ - "test", - ...testFiles, - "--max-concurrency", - "1", - "--timeout", - "30000", - ...extraArgs, - ]); + run("bun", getBunArgsForLane(lane, extraArgs)); } throw new Error(`Unknown test runtime: ${runtime}`); } -main(); +if (require.main === module) main(); + +module.exports = { getBunArgsForLane }; diff --git a/tests/README.md b/tests/README.md index 186e477b..f41a1d1d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -75,6 +75,7 @@ npm test To run the complete Jest assurance set, including the named slow security and performance lane: ```bash +npm run test:slow npm run test:all ``` @@ -82,6 +83,7 @@ To run the routine or complete assurance set with Bun: ```bash bun run test:bun +bun run test:bun:slow bun run test:bun:all ``` diff --git a/tests/scripts/test-lanes.test.ts b/tests/scripts/test-lanes.test.ts index eb0fc3b4..4f015de1 100644 --- a/tests/scripts/test-lanes.test.ts +++ b/tests/scripts/test-lanes.test.ts @@ -20,6 +20,14 @@ interface TestLaneModule { getTestFilesForLane(lane: TestLane, repoRoot: string): string[]; } +interface TestLaneRunnerModule { + getBunArgsForLane( + lane: TestLane, + extraArgs: string[], + repoRoot: string, + ): string[]; +} + const repoRoot = path.resolve(__dirname, "../.."); const lanes = require("../../scripts/test-lanes.js") as TestLaneModule; @@ -78,6 +86,32 @@ describe("test lane contract", () => { expect(lanes.getJestArgsForLane("all")).toEqual([]); }); + test("keeps routine Bun watch discovery dynamic for newly added tests", () => { + const runner = require("../../scripts/run-test-lane.js") as TestLaneRunnerModule; + const args = runner.getBunArgsForLane("routine", ["--watch"], repoRoot); + const nonWatchArgs = runner.getBunArgsForLane("routine", [], repoRoot); + + expect(args.slice(0, 2)).toEqual(["test", "./tests"]); + for (const slowPath of expectedSlowPaths) { + expect(args).toContain(`--path-ignore-patterns=${slowPath}`); + } + expect(args).toEqual( + expect.arrayContaining([ + "--max-concurrency", + "1", + "--timeout", + "30000", + "--watch", + ]), + ); + expect(args).not.toContain("tests/scripts/test-lanes.test.ts"); + expect(nonWatchArgs).toContain("tests/scripts/test-lanes.test.ts"); + expect(nonWatchArgs).not.toContain("./tests"); + for (const slowPath of expectedSlowPaths) { + expect(nonWatchArgs).not.toContain(slowPath); + } + }); + test("wires routine, slow, and complete Jest and Bun commands", () => { const packageJson = JSON.parse( readFileSync(path.join(repoRoot, "package.json"), "utf8"), From d8de419306fac9bb5956f5b159c04c2a5511ed31 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 06:06:07 -0500 Subject: [PATCH 5/9] test: support pinned Bun watch filtering --- docs/agents/runs/cleanup-1-9-ledger.md | 4 ++-- docs/agents/runs/issue-137-review-packet.md | 8 +++++--- docs/agents/runs/issue-137-session.md | 8 +++++--- scripts/run-test-lane.js | 10 ++++++---- scripts/test-lanes.js | 2 ++ tests/nip44/nip44-performance-security.test.ts | 4 ++-- tests/nip46/performance-security.test.ts | 2 +- tests/scripts/test-lanes.test.ts | 18 ++++++++++++++---- 8 files changed, 37 insertions(+), 19 deletions(-) diff --git a/docs/agents/runs/cleanup-1-9-ledger.md b/docs/agents/runs/cleanup-1-9-ledger.md index 5b707f74..eb3269fa 100644 --- a/docs/agents/runs/cleanup-1-9-ledger.md +++ b/docs/agents/runs/cleanup-1-9-ledger.md @@ -47,7 +47,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 NIP-47 service lifecycle | AFK | merged | `feature/nip47-service-lifecycle` | Grok pass; CodeRabbit local/hosted clean | Jest/Bun 1073/1073; hosted CI green | | #135 NIP-57 consolidation | AFK | merged | `feature/nip57-client-consolidation` | Grok pass; CodeRabbit local/hosted clean after fixes | Jest/Bun 1082/1082; hosted CI green | | #136 NIP-46 protocol core | AFK | merged | `feature/nip46-protocol-core` | Grok and CodeRabbit local/hosted clean after fixes | Jest/Bun 1096/1096; hosted CI green | -| #137 default test feedback loop | AFK | PR fixes | `feature/fast-default-test-loop` | Grok pass; hosted CodeRabbit fixes in review | routine 1063; slow 40; full 1103 | +| #137 default test feedback loop | AFK | PR fixes | `feature/fast-default-test-loop` | Grok compatibility fix applied; review reruns pending | routine 1063; slow 40; full 1103 | | #138 public behavior test seams | AFK | blocked by #137 | `feature/public-behavior-test-seams` | pending | pending | | #139 ephemeral Relay internals | AFK | blocked by #138 | `feature/ephemeral-relay-internals` | pending | pending | @@ -67,7 +67,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 | `2a3556d` | current Codex orchestrator; Grok 4.5 High reviewers | `569b266` plus review artifacts | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 6/6; Jest/Bun 1073/1073; all local gates and four hosted lanes green | | #135 | `25e055d` | current Codex orchestrator; Grok 4.5 High reviewers | `0909227`, `1b12872`, `b66d483` | Grok passes; CodeRabbit local/hosted clean after fixes | focused 23/23; NIP-57 41/41; Jest/Bun 1082/1082; all local gates and four hosted lanes green | | #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | PR #145 through merge `8b970e4` | Grok and CodeRabbit local/hosted clean after fixes | NIP-46 185/185; Jest/Bun 1096/1096; all local and hosted gates green | -| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`, `91ffafa`; hosted fix pending | Grok standards/spec passed; hosted CodeRabbit fixes pending clean rerun | baseline 85/1096/58.793s; routine 84/1063/32.356s; slow 2/40/43.640s; full 86/1103 | +| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`, `91ffafa`, `295d114`; Bun compatibility fix pending | Grok compatibility finding fixed; local/hosted clean reruns pending | baseline 85/1096/58.793s; routine 84/1063/32.356s; slow 2/40/43.154s; full 86/1103 | ## Alignment Decisions diff --git a/docs/agents/runs/issue-137-review-packet.md b/docs/agents/runs/issue-137-review-packet.md index b40c2b91..6bacc56b 100644 --- a/docs/agents/runs/issue-137-review-packet.md +++ b/docs/agents/runs/issue-137-review-packet.md @@ -17,9 +17,9 @@ The default Jest and Bun commands now run a canonical routine inventory, while t - `implement` session: `issue-137-session.md` - `tdd` used: lane-contract test failed before the module and wiring existed - Routine Jest: 84 suites / 1063 tests / 32.356s -- Slow Jest: 2 suites / 40 tests / 43.640s +- Slow Jest: 2 suites / 40 tests / 43.154s - Routine Bun: 84 files / 1063 tests / 190.68s -- Slow Bun: 2 files / 40 tests / 40.41s +- Slow Bun: 2 files / 40 tests / 40.42s - Full union: 86 suites/files / 1103 tests in each runtime - Complete Jest coverage command: pre-hosted-fix 86 suites / 1102 tests / 53.732s; final rerun pending @@ -38,7 +38,7 @@ SPEC_STATUS: pass SPEC_FINDINGS: - none; post-CodeRabbit Grok follow-up also passed -CODERABBIT_STATUS: local pass after fixes; hosted findings fixed, clean rerun pending +CODERABBIT_STATUS: local pass through `295d114`; Bun 1.3.9 compatibility fix rerun pending CODERABBIT_FINDINGS: - major: include Jest-compatible .spec.* files in canonical discovery — fixed with a red/green regression test - minor: assert routine and complete coverage wiring — fixed @@ -47,4 +47,6 @@ CODERABBIT_FINDINGS: - hosted minor: dynamically discover new routine tests during Bun watch without admitting slow paths — fixed with a red/green pure argument-builder test - hosted minor: document standalone Jest and Bun slow commands — fixed - hosted major: directly cover spawned Bun argument construction for dynamic watch and fixed non-watch modes — fixed +- Grok P1: replace Bun 1.3.11-only path ignores with pinned-1.3.9-compatible `[slow]` name filtering — fixed and exercised with the Bun 1.3.9 binary +- Grok P2: record hosted-fix commit `295d114` in the ledger — fixed ``` diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index fba7437e..39a174e8 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -6,7 +6,7 @@ - Fixed point before session: `8b970e4` - Worker session: current Codex orchestrator; Grok 4.5 High reviewers - Commits: `0de11d9`, `91ffafa`; final review-record commit pending -- Status: hosted CodeRabbit fixes in progress on PR #146 +- Status: Bun 1.3.9 watch compatibility fix green; local review reruns pending on PR #146 ## Inputs @@ -42,9 +42,9 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json | --- | ---: | ---: | ---: | | Baseline default Jest | 85 | 1096 | 58.793s | | Routine Jest | 84 | 1063 | 32.356s | -| Slow Jest | 2 | 40 | 43.640s | +| Slow Jest | 2 | 40 | 43.154s | | Routine Bun | 84 | 1063 | 190.68s | -| Slow Bun | 2 | 40 | 40.41s | +| Slow Bun | 2 | 40 | 40.42s | - The hosted-fix routine Jest run improved by 45.0%, exceeding the 40% target. - `input-validation` dropped from 58.171s in the baseline parallel run to 29.015s in the post-review routine run; its isolated Jest run is 25.294s. @@ -61,6 +61,7 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - CodeRabbit result: clean committed rerun with zero findings after fixes - Grok follow-up: standards and spec both passed after the CodeRabbit delta with no findings - Hosted CodeRabbit findings: accepted all four; synchronized the run status, documented standalone slow commands, and made routine Bun watch discovery dynamic through a tested pure argument builder while preserving fixed non-watch inventory +- Final Grok findings: the first hosted fix used a Bun 1.3.11-only ignore flag and the ledger omitted `295d114`; both were valid. The watch lane now uses Bun 1.3.9-supported name filtering, the slow inventory contract enforces `[slow]` on every top-level slow suite, and the ledger records the hosted-fix commit. ## Verification @@ -70,6 +71,7 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Slow Jest: 2/2 suites, 40/40 tests - Routine Bun: 84 files, 1063/1063 tests - Slow Bun: 2 files, 40/40 tests +- Pinned Bun 1.3.9 compatibility: routine name filter skipped all 40 slow tests across both slow files in 104ms while the routine lane contract ran 7/7 - Complete coverage before the hosted-fix regression test: 86/86 suites, 1102/1102 tests in 53.732s; final rerun pending - Repository gates: command/package-manager policy, ESLint, strict TypeScript, CommonJS script syntax, build, examples, pack, and diff integrity all green diff --git a/scripts/run-test-lane.js b/scripts/run-test-lane.js index 04384022..ec44d884 100644 --- a/scripts/run-test-lane.js +++ b/scripts/run-test-lane.js @@ -1,7 +1,7 @@ const path = require("path"); const { spawnSync } = require("child_process"); const { - SLOW_TEST_PATHS, + SLOW_TEST_NAME_PREFIX, getJestArgsForLane, getTestFilesForLane, } = require("./test-lanes"); @@ -22,12 +22,14 @@ function run(command, args) { function getBunArgsForLane(lane, extraArgs, root = repoRoot) { const testFiles = getTestFilesForLane(lane, root); const isRoutineWatch = lane === "routine" && extraArgs.includes("--watch"); + const escapedSlowPrefix = SLOW_TEST_NAME_PREFIX.replace( + /[.*+?^${}()|[\]\\]/g, + "\\$&", + ); const testSelection = isRoutineWatch ? [ "./tests", - ...SLOW_TEST_PATHS.map( - (filePath) => `--path-ignore-patterns=${filePath}`, - ), + `--test-name-pattern=^(?!${escapedSlowPrefix})`, ] : testFiles; diff --git a/scripts/test-lanes.js b/scripts/test-lanes.js index 48f18462..6b694943 100644 --- a/scripts/test-lanes.js +++ b/scripts/test-lanes.js @@ -5,6 +5,7 @@ const SLOW_TEST_PATHS = Object.freeze([ "tests/nip44/nip44-performance-security.test.ts", "tests/nip46/performance-security.test.ts", ]); +const SLOW_TEST_NAME_PREFIX = "[slow]"; function toPosixPath(filePath) { return filePath.split(path.sep).join("/"); @@ -62,6 +63,7 @@ function getJestArgsForLane(lane) { } module.exports = { + SLOW_TEST_NAME_PREFIX, SLOW_TEST_PATHS, discoverTestFiles, getJestArgsForLane, diff --git a/tests/nip44/nip44-performance-security.test.ts b/tests/nip44/nip44-performance-security.test.ts index e5e696ad..e8fe66d2 100644 --- a/tests/nip44/nip44-performance-security.test.ts +++ b/tests/nip44/nip44-performance-security.test.ts @@ -23,7 +23,7 @@ function measureTime(fn: () => T): { result: T; timeMs: number } { return { result, timeMs: end - start }; } -describe("NIP-44 Performance Tests", () => { +describe("[slow] NIP-44 Performance Tests", () => { const testPrivateKey = "0000000000000000000000000000000000000000000000000000000000000001"; const testPublicKey = getPublicKeyHex(testPrivateKey); @@ -193,7 +193,7 @@ describe("NIP-44 Performance Tests", () => { }); }); -describe("NIP-44 Security Tests", () => { +describe("[slow] NIP-44 Security Tests", () => { describe("Constant-Time Comparison Security", () => { test("should have consistent timing for equal arrays", () => { const array1 = new Uint8Array(32).fill(0xaa); diff --git a/tests/nip46/performance-security.test.ts b/tests/nip46/performance-security.test.ts index 8a4a2f7a..158f8ab0 100644 --- a/tests/nip46/performance-security.test.ts +++ b/tests/nip46/performance-security.test.ts @@ -10,7 +10,7 @@ import { NIP46RateLimiter } from "../../src/nip46/utils/rate-limiter"; jest.setTimeout(60000); // 60 second timeout for performance tests to handle full test suite load -describe("NIP-46 Performance & DoS Protection", () => { +describe("[slow] NIP-46 Performance & DoS Protection", () => { let relay: NostrRelay; let client: SimpleNIP46Client; let bunker: SimpleNIP46Bunker; diff --git a/tests/scripts/test-lanes.test.ts b/tests/scripts/test-lanes.test.ts index 4f015de1..edbb3341 100644 --- a/tests/scripts/test-lanes.test.ts +++ b/tests/scripts/test-lanes.test.ts @@ -15,6 +15,7 @@ type TestLane = "all" | "routine" | "slow"; interface TestLaneModule { SLOW_TEST_PATHS: string[]; + SLOW_TEST_NAME_PREFIX: string; discoverTestFiles(repoRoot: string): string[]; getJestArgsForLane(lane: TestLane): string[]; getTestFilesForLane(lane: TestLane, repoRoot: string): string[]; @@ -39,8 +40,16 @@ describe("test lane contract", () => { test("keeps one explicit sorted slow security and performance inventory", () => { expect(lanes.SLOW_TEST_PATHS).toEqual(expectedSlowPaths); + expect(lanes.SLOW_TEST_NAME_PREFIX).toBe("[slow]"); for (const relativePath of lanes.SLOW_TEST_PATHS) { - expect(existsSync(path.join(repoRoot, relativePath))).toBe(true); + const absolutePath = path.join(repoRoot, relativePath); + expect(existsSync(absolutePath)).toBe(true); + + const source = readFileSync(absolutePath, "utf8"); + const topLevelDescribes = source.match(/^describe\(/gm) ?? []; + const slowTopLevelDescribes = source.match(/^describe\("\[slow\]/gm) ?? []; + expect(topLevelDescribes.length).toBeGreaterThan(0); + expect(slowTopLevelDescribes).toHaveLength(topLevelDescribes.length); } }); @@ -92,9 +101,7 @@ describe("test lane contract", () => { const nonWatchArgs = runner.getBunArgsForLane("routine", [], repoRoot); expect(args.slice(0, 2)).toEqual(["test", "./tests"]); - for (const slowPath of expectedSlowPaths) { - expect(args).toContain(`--path-ignore-patterns=${slowPath}`); - } + expect(args).toContain("--test-name-pattern=^(?!\\[slow\\])"); expect(args).toEqual( expect.arrayContaining([ "--max-concurrency", @@ -105,6 +112,9 @@ describe("test lane contract", () => { ]), ); expect(args).not.toContain("tests/scripts/test-lanes.test.ts"); + for (const slowPath of expectedSlowPaths) { + expect(args).not.toContain(slowPath); + } expect(nonWatchArgs).toContain("tests/scripts/test-lanes.test.ts"); expect(nonWatchArgs).not.toContain("./tests"); for (const slowPath of expectedSlowPaths) { From a39ee853ef2c80da06dac0ba8288ea7cd5746073 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 06:10:09 -0500 Subject: [PATCH 6/9] docs: synchronize issue 137 commit record --- docs/agents/runs/issue-137-session.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index 39a174e8..4c4659fa 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -5,8 +5,8 @@ - Issue: #137 - Fixed point before session: `8b970e4` - Worker session: current Codex orchestrator; Grok 4.5 High reviewers -- Commits: `0de11d9`, `91ffafa`; final review-record commit pending -- Status: Bun 1.3.9 watch compatibility fix green; local review reruns pending on PR #146 +- Commits: `0de11d9`, `91ffafa`, `45a1a4f`, `295d114`, `d8de419`; final review-record commit pending +- Status: Bun 1.3.9 watch compatibility fix green; metadata review fix pending on PR #146 ## Inputs From 5a2d94bc728203eec3f66ec073879fe8e0d0c512 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 06:14:10 -0500 Subject: [PATCH 7/9] docs: clarify pinned Bun verification --- docs/agents/runs/issue-137-session.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index 4c4659fa..da525717 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -71,7 +71,7 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Slow Jest: 2/2 suites, 40/40 tests - Routine Bun: 84 files, 1063/1063 tests - Slow Bun: 2 files, 40/40 tests -- Pinned Bun 1.3.9 compatibility: routine name filter skipped all 40 slow tests across both slow files in 104ms while the routine lane contract ran 7/7 +- Pinned Bun 1.3.9 compatibility: routine name filter skipped all 40 slow tests across both slow files in 104 ms while the routine lane contract completed 7/7 checks - Complete coverage before the hosted-fix regression test: 86/86 suites, 1102/1102 tests in 53.732s; final rerun pending - Repository gates: command/package-manager policy, ESLint, strict TypeScript, CommonJS script syntax, build, examples, pack, and diff integrity all green From 2c278e7245b773a08de125f00e0bba12a1e276fa Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 06:18:21 -0500 Subject: [PATCH 8/9] docs: record final issue 137 verification --- docs/agents/runs/cleanup-1-9-ledger.md | 4 ++-- docs/agents/runs/issue-137-review-packet.md | 6 +++--- docs/agents/runs/issue-137-session.md | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/agents/runs/cleanup-1-9-ledger.md b/docs/agents/runs/cleanup-1-9-ledger.md index eb3269fa..a488d027 100644 --- a/docs/agents/runs/cleanup-1-9-ledger.md +++ b/docs/agents/runs/cleanup-1-9-ledger.md @@ -47,7 +47,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 NIP-47 service lifecycle | AFK | merged | `feature/nip47-service-lifecycle` | Grok pass; CodeRabbit local/hosted clean | Jest/Bun 1073/1073; hosted CI green | | #135 NIP-57 consolidation | AFK | merged | `feature/nip57-client-consolidation` | Grok pass; CodeRabbit local/hosted clean after fixes | Jest/Bun 1082/1082; hosted CI green | | #136 NIP-46 protocol core | AFK | merged | `feature/nip46-protocol-core` | Grok and CodeRabbit local/hosted clean after fixes | Jest/Bun 1096/1096; hosted CI green | -| #137 default test feedback loop | AFK | PR fixes | `feature/fast-default-test-loop` | Grok compatibility fix applied; review reruns pending | routine 1063; slow 40; full 1103 | +| #137 default test feedback loop | AFK | review cooldown | `feature/fast-default-test-loop` | Grok pass; final CodeRabbit retry pending after cooldown | routine 1063; slow 40; coverage 1103 | | #138 public behavior test seams | AFK | blocked by #137 | `feature/public-behavior-test-seams` | pending | pending | | #139 ephemeral Relay internals | AFK | blocked by #138 | `feature/ephemeral-relay-internals` | pending | pending | @@ -67,7 +67,7 @@ Complete cleanup items 1–9 from the staging audit end to end, branch by branch | #134 | `2a3556d` | current Codex orchestrator; Grok 4.5 High reviewers | `569b266` plus review artifacts | Grok standards/spec passed; CodeRabbit local/hosted clean | focused 6/6; Jest/Bun 1073/1073; all local gates and four hosted lanes green | | #135 | `25e055d` | current Codex orchestrator; Grok 4.5 High reviewers | `0909227`, `1b12872`, `b66d483` | Grok passes; CodeRabbit local/hosted clean after fixes | focused 23/23; NIP-57 41/41; Jest/Bun 1082/1082; all local gates and four hosted lanes green | | #136 | `ed9fa4a` | current Codex orchestrator; Grok 4.5 High reviewers | PR #145 through merge `8b970e4` | Grok and CodeRabbit local/hosted clean after fixes | NIP-46 185/185; Jest/Bun 1096/1096; all local and hosted gates green | -| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | `0de11d9`, `91ffafa`, `295d114`; Bun compatibility fix pending | Grok compatibility finding fixed; local/hosted clean reruns pending | baseline 85/1096/58.793s; routine 84/1063/32.356s; slow 2/40/43.154s; full 86/1103 | +| #137 | `8b970e4` | current Codex orchestrator; Grok 4.5 High reviewers | implementation `0de11d9`, `91ffafa`, `295d114`, `d8de419`; review records through HEAD | Grok standards/spec passed after Bun 1.3.9 fix; clean CodeRabbit retry pending | baseline 85/1096/58.793s; routine 84/1063/32.356s; slow 2/40/43.154s; coverage 86/1103 | ## Alignment Decisions diff --git a/docs/agents/runs/issue-137-review-packet.md b/docs/agents/runs/issue-137-review-packet.md index 6bacc56b..30ab6c41 100644 --- a/docs/agents/runs/issue-137-review-packet.md +++ b/docs/agents/runs/issue-137-review-packet.md @@ -21,7 +21,7 @@ The default Jest and Bun commands now run a canonical routine inventory, while t - Routine Bun: 84 files / 1063 tests / 190.68s - Slow Bun: 2 files / 40 tests / 40.42s - Full union: 86 suites/files / 1103 tests in each runtime -- Complete Jest coverage command: pre-hosted-fix 86 suites / 1102 tests / 53.732s; final rerun pending +- Complete Jest coverage command: 86 suites / 1103 tests / 49.078s; 80.51% statement coverage ## Review Instructions @@ -36,9 +36,9 @@ STANDARDS_FINDINGS: SPEC_STATUS: pass SPEC_FINDINGS: -- none; post-CodeRabbit Grok follow-up also passed +- none; final pinned-Bun Grok follow-up passed standards and spec -CODERABBIT_STATUS: local pass through `295d114`; Bun 1.3.9 compatibility fix rerun pending +CODERABBIT_STATUS: compatibility implementation clean; final wording fix committed, zero-finding retry pending after CLI cooldown CODERABBIT_FINDINGS: - major: include Jest-compatible .spec.* files in canonical discovery — fixed with a red/green regression test - minor: assert routine and complete coverage wiring — fixed diff --git a/docs/agents/runs/issue-137-session.md b/docs/agents/runs/issue-137-session.md index da525717..e42410fd 100644 --- a/docs/agents/runs/issue-137-session.md +++ b/docs/agents/runs/issue-137-session.md @@ -5,8 +5,8 @@ - Issue: #137 - Fixed point before session: `8b970e4` - Worker session: current Codex orchestrator; Grok 4.5 High reviewers -- Commits: `0de11d9`, `91ffafa`, `45a1a4f`, `295d114`, `d8de419`; final review-record commit pending -- Status: Bun 1.3.9 watch compatibility fix green; metadata review fix pending on PR #146 +- Implementation commits: `0de11d9`, `91ffafa`, `295d114`, `d8de419`; supporting review records continue through the current branch HEAD +- Status: implementation, Grok review, and final local gates green; clean CodeRabbit retry pending after cooldown on PR #146 ## Inputs @@ -62,6 +62,7 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Grok follow-up: standards and spec both passed after the CodeRabbit delta with no findings - Hosted CodeRabbit findings: accepted all four; synchronized the run status, documented standalone slow commands, and made routine Bun watch discovery dynamic through a tested pure argument builder while preserving fixed non-watch inventory - Final Grok findings: the first hosted fix used a Bun 1.3.11-only ignore flag and the ledger omitted `295d114`; both were valid. The watch lane now uses Bun 1.3.9-supported name filtering, the slow inventory contract enforces `[slow]` on every top-level slow suite, and the ledger records the hosted-fix commit. +- Final Grok result: standards and spec pass with the pinned Bun 1.3.9 evidence verified ## Verification @@ -72,7 +73,7 @@ npx jest --json --outputFile=/tmp/snstr-issue-137-baseline.json - Routine Bun: 84 files, 1063/1063 tests - Slow Bun: 2 files, 40/40 tests - Pinned Bun 1.3.9 compatibility: routine name filter skipped all 40 slow tests across both slow files in 104 ms while the routine lane contract completed 7/7 checks -- Complete coverage before the hosted-fix regression test: 86/86 suites, 1102/1102 tests in 53.732s; final rerun pending +- Complete coverage: 86/86 suites, 1103/1103 tests in 49.078s; 80.51% statements, 68.41% branches, 82.80% functions, 81.01% lines - Repository gates: command/package-manager policy, ESLint, strict TypeScript, CommonJS script syntax, build, examples, pack, and diff integrity all green ## Risks From 8dd73fba09c16980e9ba2bd934542d7914e6415b Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 19 Jul 2026 06:47:12 -0500 Subject: [PATCH 9/9] docs: separate test lane commands --- tests/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/README.md b/tests/README.md index f41a1d1d..dc6f4961 100644 --- a/tests/README.md +++ b/tests/README.md @@ -70,23 +70,25 @@ To run the routine feedback lane: ```bash npm test +bun run test:bun ``` -To run the complete Jest assurance set, including the named slow security and performance lane: +To run only the named slow security and performance lane: ```bash npm run test:slow -npm run test:all +bun run test:bun:slow ``` -To run the routine or complete assurance set with Bun: +To run the complete assurance set in either runtime: ```bash -bun run test:bun -bun run test:bun:slow +npm run test:all bun run test:bun:all ``` +Each complete command already runs its routine and slow lanes; do not run the standalone slow command first. + To run tests for a specific NIP: ```bash