From 054dc0d7572c1204b6604f4c0a554d431e86e8d1 Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Mon, 27 Apr 2026 16:55:15 -0600 Subject: [PATCH 1/5] docs: add AGENTS.md with agent guidelines for the package Co-Authored-By: Claude Sonnet 4.6 --- AGENTS.md | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a0f2be6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,178 @@ +# Agent Guidelines: @harperfast/integration-testing + +This is the `@harperfast/integration-testing` package — a framework-agnostic library for running Harper integration tests locally and ephemerally. It manages Harper child process lifecycles, allocates loopback addresses safely across concurrent test processes, and provides an optional preconfigured Node.js test runner script. + +## Repository Structure + +``` +src/ + harperLifecycle.ts # startHarper, teardownHarper, killHarper, setupHarperWithFixture, sendOperation + loopbackAddressPool.ts # Cross-process file-locked loopback address pool + run.ts # harper-integration-test-run CLI script (node:test runner) + targz.ts # Directory compression utility + index.ts # Public exports +scripts/ + setup-loopback.sh # sudo script to configure loopback addresses on macOS/Windows +dist/ # Compiled output (do not edit) +``` + +## Development + +**Build:** +```sh +npm run build # tsc -p tsconfig.build.json +``` + +**Type-check only:** +```sh +npm run check # tsc +``` + +There are no tests in this package itself. Validation is via type-checking and by using the package in dependent projects (e.g., `harperfast/harper/integrationTests`). + +**Requirements:** Node.js ≥ 20 (dev: ≥ 22), npm. + +## Key Concepts + +### Testing Ethos + +See [README.md#testing-ethos](./README.md#testing-ethos). This package is strictly for **integration** tests — Harper runs as a real child process, not a mock. Tests must be: + +- **Independent** — no shared state or ordering dependencies +- **Hermetic** — no external side effects +- **Deterministic** — same inputs, same outputs + +These properties are what make safe concurrent execution possible. + +### Loopback Address Pool + +Each concurrent Harper instance needs a distinct IP to avoid port conflicts. The pool tracks `127.0.0.1–127.0.0.N` (default N=32) in a JSON file at `$TMPDIR/harper-integration-test-loopback-pool.json`, protected by a file-based lock at `$TMPDIR/harper-integration-test-loopback-pool.lock`. + +On macOS/Windows, these addresses are not enabled by default. Run setup first: +```sh +npx harper-integration-test-setup-loopback +``` + +The pool is managed transparently by `startHarper`/`teardownHarper`. The exported pool utilities (`getNextAvailableLoopbackAddress`, `releaseLoopbackAddress`, etc.) are for advanced or custom runner use only. + +### Harper Binary Resolution + +`startHarper()` resolves the Harper binary in this order: +1. `harperBinPath` option passed to `startHarper()` +2. `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` env var +3. Auto-resolved from `harper` package in `node_modules` + +## Public API + +All exports are re-exported from `src/index.ts`. See [README.md#api](./README.md#api) for full documentation. + +**Lifecycle functions** (framework-agnostic): +- `startHarper(ctx, options?)` — allocates loopback address, creates temp dir, starts Harper, resolves when ready +- `setupHarperWithFixture(ctx, fixturePath, options?)` — like `startHarper` but pre-installs a component directory +- `killHarper(ctx)` — sends SIGTERM, waits for exit; does NOT release loopback or clean up install dir +- `teardownHarper(ctx)` — kills Harper, releases loopback address, removes install dir +- `sendOperation(context, operation)` — POST to Operations API, asserts HTTP 200 +- `createHarperContext(name?)` — creates a plain `HarperTestContext` for use outside `node:test` (e.g., Playwright) + +**Key types:** +- `HarperTestContext` — minimal shape accepted by all lifecycle functions; intentionally loose +- `HarperContext` — fully populated instance data at `ctx.harper` after `startHarper()` resolves +- `StartedHarperTestContext` — `HarperTestContext` with `harper: HarperContext` guaranteed +- `ContextWithHarper` — for `node:test` only; extends `SuiteContext & TestContext` with `harper: HarperContext` + +**Harper instance defaults** (set by `startHarper`): +- HTTP port: `9926` +- HTTPS port: `9927` (only bound when TLS/mTLS config is present) +- Operations API port: `9925` +- Admin credentials: `admin` / `Abc1234!` +- `--DEFAULTS_MODE=dev`, `--THREADS_COUNT=1` + +## Writing Tests (node:test) + +See [README.md#writing-tests](./README.md#writing-tests) for the full template and examples. + +Key rules: +- Test files: ESM TypeScript, end in `.test.ts`, begin with a comment block describing what they verify +- File names: short, hyphen-separated (e.g., `install.test.ts`, `application-management.test.ts`) +- Use `suite`/`test`/`before`/`after` from `node:test`, assertions from `node:assert/strict` +- Suites always run **sequentially**; tests within a suite run **sequentially by default** (opt into `{ concurrency: true }` per suite when safe) +- Each test file runs in its own process — files are the unit of isolation + +**Minimal template:** +```ts +/** + * Description of what this test file verifies. + */ +import { suite, test, before, after } from 'node:test'; +import { strictEqual } from 'node:assert/strict'; +import { startHarper, teardownHarper, type ContextWithHarper } from '@harperfast/integration-testing'; + +suite('short description', (ctx: ContextWithHarper) => { + before(async () => { await startHarper(ctx); }); + after(async () => { await teardownHarper(ctx); }); + + test('test description', async () => { + const response = await fetch(ctx.harper.httpURL); + strictEqual(response.status, 200); + }); +}); +``` + +## Running Tests (node:test runner) + +See [README.md#node-js-test-runner](./README.md#node-js-test-runner) for full documentation. + +```sh +npx harper-integration-test-run "integrationTests/**/*.test.ts" +``` + +Default concurrency is `floor(availableParallelism() / 2) + 1` — intentionally conservative because each Harper instance is resource-intensive. + +**Runner options** (all overridable via `HARPER_INTEGRATION_TEST_*` env vars): + +| CLI | Env var | Default | +|-----|---------|---------| +| `--concurrency=N` | `HARPER_INTEGRATION_TEST_CONCURRENCY` | `floor(parallelism/2)+1` | +| `--isolation=mode` | `HARPER_INTEGRATION_TEST_ISOLATION` | `process` | +| `--shard=index/total` | `HARPER_INTEGRATION_TEST_SHARD` | `1/1` | +| `--only` | `HARPER_INTEGRATION_TEST_ONLY` | `false` | + +Run sequentially (no loopback pool needed): +```sh +npx harper-integration-test-run --isolation=none "integrationTests/**/*.test.ts" +``` + +## Environment Variables + +| Variable | Description | +|----------|-------------| +| `HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS` | Harper startup timeout (default: 30000) | +| `HARPER_INTEGRATION_TEST_INSTALL_PARENT_DIR` | Parent dir for temp Harper install dirs (default: OS tmpdir) | +| `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` | Explicit path to Harper CLI script | +| `HARPER_INTEGRATION_TEST_LOOPBACK_POOL_COUNT` | Pool size, 1–255 (default: 32) | +| `HARPER_INTEGRATION_TEST_LOG_DIR` | If set, Harper logs are written per suite; passing suite logs are auto-deleted | +| `HARPER_INTEGRATION_TEST_CONCURRENCY` | Override runner concurrency | +| `HARPER_INTEGRATION_TEST_ISOLATION` | Override runner isolation mode | +| `HARPER_INTEGRATION_TEST_SHARD` | Override runner shard (e.g., `2/4`) | +| `HARPER_INTEGRATION_TEST_ONLY` | Override runner `--only` flag | + +## CI / GitHub Actions + +See [README.md#github-actions-workflow-parallelization](./README.md#github-actions-workflow-parallelization) for strategy guidance. Key points: + +- Default GitHub Actions runners are limited — parallelize across runners using matrix jobs + sharding, not within a single runner +- Be deliberate about when the full suite runs; consider path filters, manual triggers, or merge queues +- The [Harper integration tests workflow](https://github.com/HarperFast/harper/blob/main/.github/workflows/integration-tests.yml) is a real-world reference + +## Using Other Frameworks + +The lifecycle APIs work with any framework that supports async setup/teardown. For use outside `node:test` (e.g., Playwright), use `createHarperContext()` instead of `ContextWithHarper`: + +```ts +const ctx = createHarperContext(`worker-${workerInfo.workerIndex}`); +await startHarper(ctx); +// ... +await teardownHarper(ctx); +``` + +`src/run.ts` is the reference implementation for wiring these utilities into a runner, including concurrency and shard configuration. From 762ae14cf4d78d079ba04a6e5b5ff536bf2c2951 Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Mon, 27 Apr 2026 19:03:28 -0600 Subject: [PATCH 2/5] docs: add CONTRIBUTING.md and rewrite AGENTS.md CONTRIBUTING.md covers code organization, module system conventions, TypeScript config, scripts, dev setup, and release process. AGENTS.md is rewritten to focus on behavioral contracts, operational grounding, and known failure surfaces rather than describing the project. Co-Authored-By: Claude Sonnet 4.6 --- AGENTS.md | 184 +++++++----------------------------------------- CONTRIBUTING.md | 56 +++++++++++++++ 2 files changed, 80 insertions(+), 160 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/AGENTS.md b/AGENTS.md index a0f2be6..a7c084a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,178 +1,42 @@ -# Agent Guidelines: @harperfast/integration-testing +# AGENTS.md -This is the `@harperfast/integration-testing` package — a framework-agnostic library for running Harper integration tests locally and ephemerally. It manages Harper child process lifecycles, allocates loopback addresses safely across concurrent test processes, and provides an optional preconfigured Node.js test runner script. +## Behavioral Contracts -## Repository Structure +**Safe to run without confirmation:** +- `npm run check` — type-check only, no side effects +- `npm run build` — compiles `src/` to `dist/`, safe to re-run +- `npm install` — installs dependencies -``` -src/ - harperLifecycle.ts # startHarper, teardownHarper, killHarper, setupHarperWithFixture, sendOperation - loopbackAddressPool.ts # Cross-process file-locked loopback address pool - run.ts # harper-integration-test-run CLI script (node:test runner) - targz.ts # Directory compression utility - index.ts # Public exports -scripts/ - setup-loopback.sh # sudo script to configure loopback addresses on macOS/Windows -dist/ # Compiled output (do not edit) -``` +**Require confirmation before running:** +- `npx harper-integration-test-setup-loopback` — requires `sudo`, modifies system network interfaces +- `npm publish` — publishes to the npm registry -## Development +**Do not modify `dist/` directly.** It is generated by `npm run build`. Changes there will be overwritten. -**Build:** -```sh -npm run build # tsc -p tsconfig.build.json -``` +**Do not add tests to this package.** There is no test suite here. Validation happens via type-checking and downstream consumer projects (e.g., [`harperfast/harper`](https://github.com/HarperFast/harper)). -**Type-check only:** -```sh -npm run check # tsc -``` +## Operational Grounding -There are no tests in this package itself. Validation is via type-checking and by using the package in dependent projects (e.g., `harperfast/harper/integrationTests`). +**Module system:** The package is `"type": "module"`. All source files are ESM. Use `.ts` extensions in relative imports — `tsconfig.json` has `rewriteRelativeImportExtensions: true`, so `./foo.ts` in source becomes `./foo.js` in `dist/`. Never use `.js` extensions in `src/`. -**Requirements:** Node.js ≥ 20 (dev: ≥ 22), npm. +**`erasableSyntaxOnly: true` is enforced.** Do not use TypeScript `enum`, `namespace`, or other non-erasable syntax. -## Key Concepts +**The only public API surface is `src/index.ts`.** All consumer-facing exports must be re-exported there. Internal helpers in other `src/` files are not public. -### Testing Ethos +**Harper binary is not bundled.** `startHarper()` resolves the Harper CLI at runtime from (1) the `harperBinPath` option, (2) `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` env var, or (3) `harper` peer dependency in the consumer's `node_modules`. See [README.md#api](./README.md#api). -See [README.md#testing-ethos](./README.md#testing-ethos). This package is strictly for **integration** tests — Harper runs as a real child process, not a mock. Tests must be: +**Loopback pool state is global and file-based.** The pool JSON and lock file live in the OS tmpdir and are shared across all concurrent test processes on the machine. Bugs in pool allocation or release can leave stale lock files (`harper-integration-test-loopback-pool.lock`) that block subsequent test runs until manually deleted or until the 10-second stale timeout elapses. -- **Independent** — no shared state or ordering dependencies -- **Hermetic** — no external side effects -- **Deterministic** — same inputs, same outputs +## Failure Surface -These properties are what make safe concurrent execution possible. +**Loopback addresses must be configured before concurrent tests work on macOS/Windows.** Linux enables `127.0.0.0/8` by default; the others do not. Missing loopback aliases cause `validateLoopbackAddressPool()` to fail and the runner to exit early with a clear error. See [README.md#setup-loopback-addresses](./README.md#setup-loopback-addresses). -### Loopback Address Pool +**The file-based lock is not reentrant.** A process that calls `getNextAvailableLoopbackAddress()` twice without releasing will deadlock on the second call if no other addresses are free. This is intentional — callers must pair every `startHarper` with a `teardownHarper`. -Each concurrent Harper instance needs a distinct IP to avoid port conflicts. The pool tracks `127.0.0.1–127.0.0.N` (default N=32) in a JSON file at `$TMPDIR/harper-integration-test-loopback-pool.json`, protected by a file-based lock at `$TMPDIR/harper-integration-test-loopback-pool.lock`. +**`teardownHarper` does three things; `killHarper` does only one.** Using `killHarper` instead of `teardownHarper` in teardown hooks leaks the loopback address and leaves the temp install directory behind. Use `killHarper` only for restart scenarios where `startHarper` will be called again on the same context. -On macOS/Windows, these addresses are not enabled by default. Run setup first: -```sh -npx harper-integration-test-setup-loopback -``` +**`ctx.harper` is pre-seeded on restart.** If `ctx.harper.dataRootDir` or `ctx.harper.hostname` are already set when `startHarper` is called, they are reused instead of allocating new ones. This is intentional for restart test scenarios. Do not mutate `ctx.harper` manually. -The pool is managed transparently by `startHarper`/`teardownHarper`. The exported pool utilities (`getNextAvailableLoopbackAddress`, `releaseLoopbackAddress`, etc.) are for advanced or custom runner use only. +**`run.ts` must remain stateless.** It is the CLI entry point and must not contain setup/teardown logic or hold mutable state. All lifecycle management belongs in individual test suites via the lifecycle APIs. See the comment at the top of [`src/run.ts`](./src/run.ts). -### Harper Binary Resolution - -`startHarper()` resolves the Harper binary in this order: -1. `harperBinPath` option passed to `startHarper()` -2. `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` env var -3. Auto-resolved from `harper` package in `node_modules` - -## Public API - -All exports are re-exported from `src/index.ts`. See [README.md#api](./README.md#api) for full documentation. - -**Lifecycle functions** (framework-agnostic): -- `startHarper(ctx, options?)` — allocates loopback address, creates temp dir, starts Harper, resolves when ready -- `setupHarperWithFixture(ctx, fixturePath, options?)` — like `startHarper` but pre-installs a component directory -- `killHarper(ctx)` — sends SIGTERM, waits for exit; does NOT release loopback or clean up install dir -- `teardownHarper(ctx)` — kills Harper, releases loopback address, removes install dir -- `sendOperation(context, operation)` — POST to Operations API, asserts HTTP 200 -- `createHarperContext(name?)` — creates a plain `HarperTestContext` for use outside `node:test` (e.g., Playwright) - -**Key types:** -- `HarperTestContext` — minimal shape accepted by all lifecycle functions; intentionally loose -- `HarperContext` — fully populated instance data at `ctx.harper` after `startHarper()` resolves -- `StartedHarperTestContext` — `HarperTestContext` with `harper: HarperContext` guaranteed -- `ContextWithHarper` — for `node:test` only; extends `SuiteContext & TestContext` with `harper: HarperContext` - -**Harper instance defaults** (set by `startHarper`): -- HTTP port: `9926` -- HTTPS port: `9927` (only bound when TLS/mTLS config is present) -- Operations API port: `9925` -- Admin credentials: `admin` / `Abc1234!` -- `--DEFAULTS_MODE=dev`, `--THREADS_COUNT=1` - -## Writing Tests (node:test) - -See [README.md#writing-tests](./README.md#writing-tests) for the full template and examples. - -Key rules: -- Test files: ESM TypeScript, end in `.test.ts`, begin with a comment block describing what they verify -- File names: short, hyphen-separated (e.g., `install.test.ts`, `application-management.test.ts`) -- Use `suite`/`test`/`before`/`after` from `node:test`, assertions from `node:assert/strict` -- Suites always run **sequentially**; tests within a suite run **sequentially by default** (opt into `{ concurrency: true }` per suite when safe) -- Each test file runs in its own process — files are the unit of isolation - -**Minimal template:** -```ts -/** - * Description of what this test file verifies. - */ -import { suite, test, before, after } from 'node:test'; -import { strictEqual } from 'node:assert/strict'; -import { startHarper, teardownHarper, type ContextWithHarper } from '@harperfast/integration-testing'; - -suite('short description', (ctx: ContextWithHarper) => { - before(async () => { await startHarper(ctx); }); - after(async () => { await teardownHarper(ctx); }); - - test('test description', async () => { - const response = await fetch(ctx.harper.httpURL); - strictEqual(response.status, 200); - }); -}); -``` - -## Running Tests (node:test runner) - -See [README.md#node-js-test-runner](./README.md#node-js-test-runner) for full documentation. - -```sh -npx harper-integration-test-run "integrationTests/**/*.test.ts" -``` - -Default concurrency is `floor(availableParallelism() / 2) + 1` — intentionally conservative because each Harper instance is resource-intensive. - -**Runner options** (all overridable via `HARPER_INTEGRATION_TEST_*` env vars): - -| CLI | Env var | Default | -|-----|---------|---------| -| `--concurrency=N` | `HARPER_INTEGRATION_TEST_CONCURRENCY` | `floor(parallelism/2)+1` | -| `--isolation=mode` | `HARPER_INTEGRATION_TEST_ISOLATION` | `process` | -| `--shard=index/total` | `HARPER_INTEGRATION_TEST_SHARD` | `1/1` | -| `--only` | `HARPER_INTEGRATION_TEST_ONLY` | `false` | - -Run sequentially (no loopback pool needed): -```sh -npx harper-integration-test-run --isolation=none "integrationTests/**/*.test.ts" -``` - -## Environment Variables - -| Variable | Description | -|----------|-------------| -| `HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS` | Harper startup timeout (default: 30000) | -| `HARPER_INTEGRATION_TEST_INSTALL_PARENT_DIR` | Parent dir for temp Harper install dirs (default: OS tmpdir) | -| `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` | Explicit path to Harper CLI script | -| `HARPER_INTEGRATION_TEST_LOOPBACK_POOL_COUNT` | Pool size, 1–255 (default: 32) | -| `HARPER_INTEGRATION_TEST_LOG_DIR` | If set, Harper logs are written per suite; passing suite logs are auto-deleted | -| `HARPER_INTEGRATION_TEST_CONCURRENCY` | Override runner concurrency | -| `HARPER_INTEGRATION_TEST_ISOLATION` | Override runner isolation mode | -| `HARPER_INTEGRATION_TEST_SHARD` | Override runner shard (e.g., `2/4`) | -| `HARPER_INTEGRATION_TEST_ONLY` | Override runner `--only` flag | - -## CI / GitHub Actions - -See [README.md#github-actions-workflow-parallelization](./README.md#github-actions-workflow-parallelization) for strategy guidance. Key points: - -- Default GitHub Actions runners are limited — parallelize across runners using matrix jobs + sharding, not within a single runner -- Be deliberate about when the full suite runs; consider path filters, manual triggers, or merge queues -- The [Harper integration tests workflow](https://github.com/HarperFast/harper/blob/main/.github/workflows/integration-tests.yml) is a real-world reference - -## Using Other Frameworks - -The lifecycle APIs work with any framework that supports async setup/teardown. For use outside `node:test` (e.g., Playwright), use `createHarperContext()` instead of `ContextWithHarper`: - -```ts -const ctx = createHarperContext(`worker-${workerInfo.workerIndex}`); -await startHarper(ctx); -// ... -await teardownHarper(ctx); -``` - -`src/run.ts` is the reference implementation for wiring these utilities into a runner, including concurrency and shard configuration. +**`tar-fs` is the only runtime dependency.** Keep it that way unless there is a strong reason. This package is installed as a `devDependency` by consumers; dependency bloat has real cost. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..784cc4c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,56 @@ +# Contributing + +## Code Organization + +``` +src/ + harperLifecycle.ts # startHarper, teardownHarper, killHarper, setupHarperWithFixture, sendOperation, createHarperContext + loopbackAddressPool.ts # File-locked cross-process loopback address pool + run.ts # harper-integration-test-run CLI entry point + targz.ts # Directory → base64 tar.gz utility + index.ts # Public re-exports (the package's only entry point) +scripts/ + setup-loopback.sh # sudo script to configure loopback aliases (macOS/Windows) +``` + +The published package includes `dist/`, `scripts/`, `api.md`, and `README.md`. + +## Module System + +The package is `"type": "module"` — all source files are ESM. TypeScript is configured with `"module": "NodeNext"` and `"rewriteRelativeImportExtensions": true`, which means: + +- All relative imports in source use `.ts` extensions (e.g., `import { foo } from './foo.ts'`) +- `tsc` rewrites these to `.js` in the compiled output + +Do not use `.js` extensions in source imports. + +## TypeScript Configuration + +There are two `tsconfig` files: + +- `tsconfig.json` — type-checking only (`"noEmit": true`). Used by `npm run check` and editors. +- `tsconfig.build.json` — emits to `dist/` with source maps and declarations. Used by `npm run build`. + +`erasableSyntaxOnly: true` is set, meaning TypeScript-only syntax that cannot be stripped (e.g., `enum`, `namespace`) is not allowed. + +## Scripts + +```sh +npm run check # Type-check only (no output) +npm run build # Compile src/ → dist/ +``` + +There are no automated tests in this package. Validation is type-checking plus manual testing via dependent projects. + +## Development Setup + +1. Install dependencies: `npm install` +2. On macOS or Windows, configure loopback addresses before running integration tests in dependent projects: + ```sh + npx harper-integration-test-setup-loopback + ``` + This requires `sudo`. Defaults to 32 addresses (`127.0.0.1–127.0.0.32`). Override with `HARPER_INTEGRATION_TEST_LOOPBACK_POOL_COUNT`. + +## Releases + +Update the `version` field in `package.json` and publish via `npm publish`. The `files` field in `package.json` controls what is included in the published package. From e962c1f6e22c5b1bc625f7d4c9beae968e98ab20 Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Mon, 27 Apr 2026 19:34:52 -0600 Subject: [PATCH 3/5] okay fine ill do it myself --- AGENTS.md | 61 +++++++++++++++++-------------------------------- CONTRIBUTING.md | 39 ++++++------------------------- 2 files changed, 28 insertions(+), 72 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a7c084a..ac645a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,42 +1,23 @@ # AGENTS.md -## Behavioral Contracts - -**Safe to run without confirmation:** -- `npm run check` — type-check only, no side effects -- `npm run build` — compiles `src/` to `dist/`, safe to re-run -- `npm install` — installs dependencies - -**Require confirmation before running:** -- `npx harper-integration-test-setup-loopback` — requires `sudo`, modifies system network interfaces -- `npm publish` — publishes to the npm registry - -**Do not modify `dist/` directly.** It is generated by `npm run build`. Changes there will be overwritten. - -**Do not add tests to this package.** There is no test suite here. Validation happens via type-checking and downstream consumer projects (e.g., [`harperfast/harper`](https://github.com/HarperFast/harper)). - -## Operational Grounding - -**Module system:** The package is `"type": "module"`. All source files are ESM. Use `.ts` extensions in relative imports — `tsconfig.json` has `rewriteRelativeImportExtensions: true`, so `./foo.ts` in source becomes `./foo.js` in `dist/`. Never use `.js` extensions in `src/`. - -**`erasableSyntaxOnly: true` is enforced.** Do not use TypeScript `enum`, `namespace`, or other non-erasable syntax. - -**The only public API surface is `src/index.ts`.** All consumer-facing exports must be re-exported there. Internal helpers in other `src/` files are not public. - -**Harper binary is not bundled.** `startHarper()` resolves the Harper CLI at runtime from (1) the `harperBinPath` option, (2) `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` env var, or (3) `harper` peer dependency in the consumer's `node_modules`. See [README.md#api](./README.md#api). - -**Loopback pool state is global and file-based.** The pool JSON and lock file live in the OS tmpdir and are shared across all concurrent test processes on the machine. Bugs in pool allocation or release can leave stale lock files (`harper-integration-test-loopback-pool.lock`) that block subsequent test runs until manually deleted or until the 10-second stale timeout elapses. - -## Failure Surface - -**Loopback addresses must be configured before concurrent tests work on macOS/Windows.** Linux enables `127.0.0.0/8` by default; the others do not. Missing loopback aliases cause `validateLoopbackAddressPool()` to fail and the runner to exit early with a clear error. See [README.md#setup-loopback-addresses](./README.md#setup-loopback-addresses). - -**The file-based lock is not reentrant.** A process that calls `getNextAvailableLoopbackAddress()` twice without releasing will deadlock on the second call if no other addresses are free. This is intentional — callers must pair every `startHarper` with a `teardownHarper`. - -**`teardownHarper` does three things; `killHarper` does only one.** Using `killHarper` instead of `teardownHarper` in teardown hooks leaks the loopback address and leaves the temp install directory behind. Use `killHarper` only for restart scenarios where `startHarper` will be called again on the same context. - -**`ctx.harper` is pre-seeded on restart.** If `ctx.harper.dataRootDir` or `ctx.harper.hostname` are already set when `startHarper` is called, they are reused instead of allocating new ones. This is intentional for restart test scenarios. Do not mutate `ctx.harper` manually. - -**`run.ts` must remain stateless.** It is the CLI entry point and must not contain setup/teardown logic or hold mutable state. All lifecycle management belongs in individual test suites via the lifecycle APIs. See the comment at the top of [`src/run.ts`](./src/run.ts). - -**`tar-fs` is the only runtime dependency.** Keep it that way unless there is a strong reason. This package is installed as a `devDependency` by consumers; dependency bloat has real cost. +Review the `README.md` and `CONTRIBUTING.md` for all relevant repository information. + +## Development Tips +- Ensure you're on at least Node.js v22 or greater when contributing +- Use `npm install` to install dependencies +- Use `npm run build` to build the project in preparation for publishing +- Do not run `npm version` or `npm publish`; these commands are for humans only. +- When updating core code, make sure to update relevant documentation. + - Public API and usage docs are in `README.md` + - Internal documentation is in `CONTRIBUTING.md` + - If you change the public API surface in `src/index.ts`, update `README.md#api`. + +## Code Style +- Use ESM and TypeScript +- Use erasable syntax only (no `enum` or `namespace`) +- There is currently no linter or formatter for this project + +## Testing Tips +- Use `npm link` in this directory and `npm link @harperfast/integration-testing` in other project directories to test out changes with existing +- Use `npm run check` to type-check the project without generating a build output +- There is currently no tests for this project diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 784cc4c..3c78fda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,30 +1,14 @@ # Contributing -## Code Organization - -``` -src/ - harperLifecycle.ts # startHarper, teardownHarper, killHarper, setupHarperWithFixture, sendOperation, createHarperContext - loopbackAddressPool.ts # File-locked cross-process loopback address pool - run.ts # harper-integration-test-run CLI entry point - targz.ts # Directory → base64 tar.gz utility - index.ts # Public re-exports (the package's only entry point) -scripts/ - setup-loopback.sh # sudo script to configure loopback aliases (macOS/Windows) -``` - -The published package includes `dist/`, `scripts/`, `api.md`, and `README.md`. +Contributors are encouraged to communicate with maintainers in issues or other channels (such as our community [Discord](https://harper.fast/discord)) before submitting changes. -## Module System - -The package is `"type": "module"` — all source files are ESM. TypeScript is configured with `"module": "NodeNext"` and `"rewriteRelativeImportExtensions": true`, which means: +## Code Organization -- All relative imports in source use `.ts` extensions (e.g., `import { foo } from './foo.ts'`) -- `tsc` rewrites these to `.js` in the compiled output +Source files are located in `src/`. These are built to the `dist/` directory. The published package includes `dist/`, `scripts/`, and the regular npm metadata and documentation files. -Do not use `.js` extensions in source imports. +The `src/index.ts` is the source for the main export. This is the public re-export of all the various utilities from `src/harperLifecycle.ts`, `targz.ts`, and more. The `src/run.ts` is the source for the `harper-integration-test-run` bin script. And the `scripts/setup-loopback.sh` is the source for the `harper-integration-test-setup-loopback` bin script. -## TypeScript Configuration +The package is `"type": "module"` — all source files are ESM by default. There are two `tsconfig` files: @@ -40,17 +24,8 @@ npm run check # Type-check only (no output) npm run build # Compile src/ → dist/ ``` -There are no automated tests in this package. Validation is type-checking plus manual testing via dependent projects. - -## Development Setup - -1. Install dependencies: `npm install` -2. On macOS or Windows, configure loopback addresses before running integration tests in dependent projects: - ```sh - npx harper-integration-test-setup-loopback - ``` - This requires `sudo`. Defaults to 32 addresses (`127.0.0.1–127.0.0.32`). Override with `HARPER_INTEGRATION_TEST_LOOPBACK_POOL_COUNT`. +There are no automated tests in this package yet. Validation is type-checking plus manual testing via dependent projects. ## Releases -Update the `version` field in `package.json` and publish via `npm publish`. The `files` field in `package.json` controls what is included in the published package. +Update the `version` field in `package.json` (recommend using `npm version `) and publish via `npm publish`. The `files` field in `package.json` controls what is included in the published package. Don't forget to push the version commit and tag. From 49416cb4804c57cc78f625a29ebc72b9764b4f5d Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Mon, 27 Apr 2026 20:14:52 -0600 Subject: [PATCH 4/5] edits --- AGENTS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index ac645a1..4e9ad13 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,6 +11,7 @@ Review the `README.md` and `CONTRIBUTING.md` for all relevant repository informa - Public API and usage docs are in `README.md` - Internal documentation is in `CONTRIBUTING.md` - If you change the public API surface in `src/index.ts`, update `README.md#api`. +- Do not edit files in `dist/`; it is compiled output and gitignored. ## Code Style - Use ESM and TypeScript @@ -18,6 +19,6 @@ Review the `README.md` and `CONTRIBUTING.md` for all relevant repository informa - There is currently no linter or formatter for this project ## Testing Tips -- Use `npm link` in this directory and `npm link @harperfast/integration-testing` in other project directories to test out changes with existing +- Use `npm link` in this directory and `npm link @harperfast/integration-testing` in other project directories to test out changes locally - Use `npm run check` to type-check the project without generating a build output - There is currently no tests for this project From b204905c75da9a835b696406740312bd52f2b7a7 Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Mon, 27 Apr 2026 20:17:23 -0600 Subject: [PATCH 5/5] more edits --- AGENTS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 4e9ad13..af4d15d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ Review the `README.md` and `CONTRIBUTING.md` for all relevant repository informa ## Development Tips - Ensure you're on at least Node.js v22 or greater when contributing - Use `npm install` to install dependencies -- Use `npm run build` to build the project in preparation for publishing +- Use `npm run build` to build the project - Do not run `npm version` or `npm publish`; these commands are for humans only. - When updating core code, make sure to update relevant documentation. - Public API and usage docs are in `README.md` @@ -21,4 +21,4 @@ Review the `README.md` and `CONTRIBUTING.md` for all relevant repository informa ## Testing Tips - Use `npm link` in this directory and `npm link @harperfast/integration-testing` in other project directories to test out changes locally - Use `npm run check` to type-check the project without generating a build output -- There is currently no tests for this project +- There are currently no tests for this project