Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
# `testing/`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Provides `run2pcParticipantConformance(factory)` — a runnable test
suite that pins the contract every 2PC writer participant MUST honour.
Adapter authors drop a single import + invocation into a
`tests/conformance/run-2pc-participant.test.ts` file in their package;
the harness handles the rest.
Shipping the harness on this package's `./testing` subpath keeps
participants accountable to the same prepare/commit/rollback semantics
the coordinator depends on at runtime. Without this harness, drift
between participant implementations would only surface during
integration testing — too late.
## Features
- Six pinned invariants (engine identifier, voter mode, prepare-then-
prepare-SQL, commit-prepared, rollback-prepared, idempotency-on-
second-rollback).
- Per-scenario factory: every test starts from a fresh participant +
teardown so the suite is isolation-safe under parallel runs.
- Uses `@suaveplan/testing/runner` — works under both Vitest and
Bun:test without re-importing.
- Generates unique gids per scenario so re-runs do not collide.
## Usage: Basic
```ts
// In an adapter package's tests/conformance/run-2pc-participant.test.ts
import { run2pcParticipantConformance } from "@suaveplan/api-2pc/testing";
import { createMyParticipant, teardownMyParticipant } from "../helpers";
run2pcParticipantConformance({
async create() {
const participant = await createMyParticipant();
return {
participant,
teardown: () => teardownMyParticipant(participant),
};
},
});
```
## Usage: Advanced
The harness exposes no surface beyond `run2pcParticipantConformance` —
deliberately. Adapter-specific assertions belong in adapter test
files, not in the conformance harness. If your adapter needs to
exercise behaviour the suite does not cover (e.g. cancellation,
custom serialization), add a sibling test file:
```ts
import { describe, it } from "@suaveplan/testing/runner";
import { run2pcParticipantConformance } from "@suaveplan/api-2pc/testing";
describe("my-participant", () => {
run2pcParticipantConformance({ create: createMyParticipant });
it("cancels a stuck prepare on signal abort", { timeout: 30_000 }, async () => {
// adapter-specific assertion
});
});
```
## API Reference
- `interface TwoPcParticipantFactory`
- `create(): Promise<{ participant: RegisteredTwoPcParticipant; teardown: () => Promise<void> }>`
- `function run2pcParticipantConformance(factory): void`
- Registers six `describe`/`it` blocks against the surrounding
runner. Returns nothing.
## Implementation Notes
The harness deliberately does NOT use a shared Postgres connection
across scenarios. Each scenario calls `factory.create()` to get a
fresh participant; the factory is expected to wire its own connection
(directly to a Postgres container, against a shared pool, or against
an `env-bridge` passthrough URL). This isolation prevents one
scenario's leftover prepared transactions from contaminating the
next.
Gids embed `Date.now()` + a random suffix so re-runs within the same
millisecond never collide on the underlying `pg_prepared_xacts`
table. The cleanup `ROLLBACK PREPARED` at the end of the
prepare-only scenario is best-effort: failure to roll back leaves
the gid prepared until the next teardown sweep, but the harness's
own teardown handle is the primary cleanup path.
The harness is intentionally NOT exported from the package root (`./`
subpath) — only `./testing`. This mirrors the convention used by
sibling packages (`@suaveplan/i18n-shared/testing`,
`@suaveplan/api-host/testing`) so production code can not accidentally
depend on test-only symbols.