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,85 @@
# upgrade
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns `upgradeSurface` and the `MigrationRegistry` chain that
walks an older schema-version document forward to the current version.
Without an explicit upgrade path consumers cannot read documents created
by previous releases of the package; with it, each release registers a
single forward edge and old documents survive arbitrarily many bumps.
## Features
- `MigrationRegistry` — ordered registry keyed by `from` version, with
`register`, `get`, and `list` accessors.
- `Migration` — `{ from; to; apply: (unknown) => unknown }` — pure
function transforming a versioned document one step forward.
- `defaultRegistry` — package-wide instance consumers extend as new
schema versions ship.
- `upgradeSurface` — walks the registry chain, validates the output
against the strict-root schema, and returns a typed `ControlSurface`.
- Five distinct failure modes mapped onto two error codes:
`INVALID_DOCUMENT` (envelope not parseable) and `UNSUPPORTED_VERSION`
(no migration registered) plus `UPGRADE_FAILED` (every other failure
during the chain walk).
## Usage: Basic Example
Read a v0.0.9 document and walk it forward through the default chain:
```ts
import { upgradeSurface } from "@suaveplan/control-surface-schema";
const surface = upgradeSurface(JSON.parse(await fs.readFile(path, "utf8")));
console.log("Loaded surface", surface.id, "at", surface.version);
```
## Usage: Advanced Example
Register a custom migration in an isolated registry for tests:
```ts
import {
MigrationRegistry,
upgradeSurface,
} from "@suaveplan/control-surface-schema";
const registry = new MigrationRegistry();
registry.register({
from: "0.0.9",
to: "0.1.0",
apply: (doc) => {
const next = { ...(doc as Record<string, unknown>) };
next.version = "0.1.0";
if (typeof next.skin === "string") next.skin = { id: next.skin };
return next;
},
});
const upgraded = upgradeSurface(legacyDoc, { registry });
```
## API Reference
- `interface Migration` — `{ from; to; apply }`.
- `class MigrationRegistry` — `register(migration)`, `get(from)`, `list()`.
- `defaultRegistry: MigrationRegistry` — package-wide chain.
- `interface UpgradeOptions` — `{ registry? }`.
- `upgradeSurface(input: unknown, options?: UpgradeOptions): ControlSurface`.
## Implementation Notes
Migrations are chained by `from` version, not by index, so the registry
is a true DAG keyed by source version. Duplicate registration of the
same `from` rejects with `UPGRADE_FAILED` because forking forward edges
would make the resolution non-deterministic. The walker keeps a hop
counter equal to `registry.list().length + 1` so a corrupt registry
that loops back to a prior version trips `UPGRADE_FAILED` instead of
running forever. After the chain completes the function re-runs
`validateSurface` to catch migrations that emit structurally invalid
documents — the schema is the source of truth, not the migration's word
that it produced a valid output.