Two defects shipped with #8770, both red on release/v3.8.49.
1. `OMNIROUTE_EXTRA_MIGRATIONS_DIRS` was documented in ENVIRONMENT.md but never
added to .env.example, so the env/docs contract gate and its two tests
(check-env-doc-sync, issue-7793-env-doc-sync-repro) failed. Added, with the
same explanation the docs carry.
2. tests/unit/db-migration-runner-extra-dirs.test.ts passed locally and failed on
CI, for two reasons that only appear under the CI invocation:
- It re-imported migrationRunner.ts under a cache-busting query string to pick
up a fresh `MIGRATIONS_DIR` per test. That is not reliable under the loader
chain CI uses (`--import tsx/esm --import setupPolyfill --import
isolateDataDir`): the second test got a runner still pointing at the REAL
migrations directory and tried to apply migration 127 to an empty in-memory
DB. The core directory is now fixed once, before the first import; only the
extra directories vary per test, and those are resolved at call time by
design.
- Tests were registered with top-level `await`. With synchronous bodies that
drains the event loop between tests and `--test-force-exit` — used by every
CI test script — cancels the remainder of the file.
Both constraints are now written down in the file header so the next edit does
not reintroduce them.
Validated with the exact CI invocation, not the bare runner: 11/11, 0 cancelled.
Neighbouring suites green under the same flags: db-migration-runner (26),
check-migration-numbering (15), db-migrationrunner-constants-split (7),
db-migration-version-uniqueness (2), check-env-doc-sync (13),
issue-7793-env-doc-sync-repro (1).
The runner reads exactly one directory and records the bare numeric prefix as the
version, so the numeric slots are a single global namespace. Any distribution that
ships its own migrations next to the upstream set has to draw from that same range
while upstream keeps appending to it — and when both sides claim a number, the
runner records one name for it and treats the other as already applied. That
migration then never runs, silently, on every already-provisioned database.
OMNIROUTE_EXTRA_MIGRATIONS_DIRS registers additional directories as
`namespace=dir` entries separated by the platform path delimiter. Files found
there are recorded as `<namespace>-<number>` (e.g. `ee-134`), a version space that
cannot collide with the upstream numeric one, and they are applied after the core
set. Unset — the default, and the only case for a plain install — nothing changes:
no filesystem access, identical behaviour.
Misconfiguration throws instead of being skipped. A malformed entry, a namespace
outside [a-z][a-z0-9]*, a duplicate namespace, or a directory that does not exist
aborts startup, because silently missing schema is the exact failure this exists to
prevent. Two files sharing a number inside the SAME namespace still collide and
throw, mirroring the runner's own guard.
Also fixes an inconsistency the tests surfaced: a missing core directory returned
early and took the extra directories down with it. They are an independent set.
The version-namespaced strings need no further plumbing — the applied set, the gap
reconciliation and the name-mismatch check all key on the version string, and the
numeric-only paths (`Number.parseInt`, the "032"/"041"/"042" special cases,
`isSchemaAlreadyApplied`) ignore them by construction.
11 new tests; the 7 neighbouring migration suites stay green (62 tests).