Research: strict TypeScript runtime and toolchain
Baseline#
До эксперимента репозиторий был ESM-проектом с npm lockfile. Целевой вопрос не
сводился к «умеет ли runtime прочитать .ts»: требовались одновременно
статическая строгость, прямой запуск Node 24, Bun runtime compatibility и
отсутствие второго lockfile.
Важное разделение:
- Runtime execution удаляет/транспилирует типы и запускает JavaScript.
- Type safety доказывается отдельным
tsc --noEmit. - Install reproducibility задаётся только npm manifest + npm lockfile.
- Bun compatibility здесь означает smoke execution, а не переход на Bun package manager и не обещание полной API-совместимости.
Метод#
- Зафиксировать версии локального runtime/toolchain и корневых manifest/lock.
- Проверить официальные контракты Node, Bun, TypeScript и npm.
- До реализации создать regression tests для npm-only invariants и получить RED из-за отсутствующего verifier.
- Реализовать один erasable-syntax TypeScript verifier только на
node:built-ins. - Выполнить strict typecheck, tests под Node и Bun, затем по одному CLI-запуску verifier в каждом runtime.
- Сопоставить текущие версии библиотек с минимальными потребностями прототипа. Сетевые LLM-вызовы не выполнять.
Контролируемые переменные: один checkout, один package-lock.json, одинаковый
.ts entry point и одинаковые package metadata. Runtime менялся только между
Node и Bun. Каждый CLI smoke выполнен один раз; unit tests выполнены по одному
разу в каждом runtime.
Реестр доказательств#
| ID | Тип | Описание | Источник, путь или команда | Дата или версия |
|---|---|---|---|---|
| E-001 | Measurement | macOS 26.4 build 25E246, arm64 | sw_vers; uname -m |
2026-07-25 |
| E-002 | Measurement | Node 24.14.0, npm 11.9.0, Bun 1.3.6 | node --version; npm --version; bun --version |
2026-07-25 |
| E-003 | Fact | Node 24 type stripping стабилен, выполняет erasable syntax, не type-checks и игнорирует tsconfig.json |
Node.js TypeScript docs | accessed 2026-07-25; Node 24 |
| E-004 | Fact | Bun напрямую запускает TypeScript и поддерживает Node-style resolution | Bun TypeScript runtime, module resolution | accessed 2026-07-25; Bun 1.3.6 |
| E-005 | Fact | bun install импортирует npm lock и создаёт bun.lock; поэтому он не входит в выбранный workflow |
Bun lockfiles, migration from npm | accessed 2026-07-25; Bun 1.3 |
| E-006 | Fact | strict включает семейство строгих type checks; NodeNext моделирует современный Node ESM/CJS contract |
TS strict, TS module | accessed 2026-07-25; TypeScript 7.0.2 |
| E-007 | Fact | TypeScript 7.0 использует новый compiler, но сохраняет tsc CLI; stable compiler API ещё не является основанием решения |
TypeScript 7.0 announcement | accessed 2026-07-25; TypeScript 7.0 |
| E-008 | Fact | npm lockfile описывает точное дерево установки и предназначен для commit в source repository | npm package-lock docs | accessed 2026-07-25; npm 11 |
| E-009 | Measurement | Root pins: TypeScript 7.0.2, @types/node 24.13.3, Ajv 8.20.0, fast-check 4.9.0; lockfile v3 совпадает |
package.json; package-lock.json; verifier |
2026-07-25 |
| E-010 | Fact | Ajv имеет TypeScript utility types/type guards и strict schema mode | Ajv TypeScript guide, Ajv options | accessed 2026-07-25; Ajv 8.20.0 |
| E-011 | Fact | fast-check генерирует и shrink-ит cases; подходит для invariants/model-based tests и не привязан к одному test runner | fast-check docs | accessed 2026-07-25; fast-check 4.9.0 |
| E-012 | Fact | XState предоставляет actors/statecharts для сложных lifecycle | XState docs | accessed 2026-07-25; XState 5.32.5 |
| E-013 | Fact | json-rules-engine исполняет JSON all/any conditions с priorities и fact caching |
json-rules-engine repository | accessed 2026-07-25; 7.3.1 |
| E-014 | Fact | Graphology — graph structure с сериализацией и отдельной standard library алгоритмов | Graphology docs | accessed 2026-07-25; 0.26.0 |
| E-015 | Fact | Graphlib реализует directed/undirected multigraph и базовые graph algorithms | Graphlib repository | accessed 2026-07-25; @dagrejs/graphlib 4.0.1 |
| E-016 | Fact | EventStore client поддерживает expected revision/optimistic concurrency; исследованный npm client помечен legacy | Kurrent legacy Node client docs | accessed 2026-07-25; @eventstore/db-client 6.2.1 |
| E-017 | Fact | node:sqlite доступен в Node 24, но stability status менялся внутри release line; Bun parity этим источником не подтверждена |
Node 24 SQLite docs | accessed 2026-07-25; Node 24 |
| E-018 | Fact | OpenTelemetry JS: traces/metrics stable, logs ещё development | OpenTelemetry JS, instrumentation | accessed 2026-07-25; @opentelemetry/sdk-node 0.221.0 |
| E-019 | Fact | LangSmith поддерживает offline/online evals, code evaluators и LLM-as-judge | LangSmith evaluation docs | accessed 2026-07-25; LangSmith 0.8.7 |
| E-020 | Fact | Braintrust CLI может запускать local evaluation без отправки logs; managed upload остаётся отдельным выбором | Braintrust evaluation docs | accessed 2026-07-25; Braintrust 3.24.0 |
| E-021 | Fact | Phoenix принимает OpenTelemetry traces и предлагает self-hosted tracing/evals/datasets | Phoenix docs | accessed 2026-07-25; service/protocol candidate |
| E-022 | Fact | OpenAI Structured Outputs ограничивают output JSON Schema; application semantic validation всё равно требуется | OpenAI Structured Outputs | accessed 2026-07-25; OpenAI SDK 6.49.0 |
| E-023 | Fact | OpenAI prompt caching зависит от общего exact prefix и сообщает cache token counters | OpenAI prompt caching | accessed 2026-07-25 |
| E-024 | Fact | Anthropic предоставляет JSON outputs/strict tool use с ограниченным JSON Schema contract | Anthropic structured outputs | accessed 2026-07-25; Anthropic SDK 0.115.0 |
| E-025 | Fact | Anthropic cache использует prefix/breakpoints и возвращает cache read/write usage | Anthropic prompt caching | accessed 2026-07-25 |
| E-026 | Fact | Gemini structured output поддерживает subset JSON Schema и требует отдельной semantic validation; caching бывает implicit/explicit | Gemini structured output, context caching | accessed 2026-07-25; Google Gen AI SDK 2.13.0 |
| E-027 | Measurement | RED: test runner завершился exit 1 с ERR_MODULE_NOT_FOUND до появления verifier |
node --test .../verify-toolchain.test.ts |
2026-07-25T01:05+07:00 |
| E-028 | Measurement | TypeScript 7.0.2 strict typecheck завершился exit 0 | ./node_modules/.bin/tsc -p .../prototype/tsconfig.json |
2026-07-25T01:08+07:00 |
| E-029 | Measurement | Node tests: 2 pass, 0 fail | node --test .../verify-toolchain.test.ts |
Node 24.14.0 |
| E-030 | Measurement | Node verifier: ok: true; Node 24.14.0; npm lock invariants прошли |
node .../verify-toolchain.ts --expect-runtime=node |
2026-07-25T01:08+07:00 |
| E-031 | Measurement | Bun verifier: ok: true; Bun 1.3.6; bun.lock* отсутствуют; Bun reports Node compatibility 24.3.0 |
bun run .../verify-toolchain.ts --expect-runtime=bun |
2026-07-25T01:08+07:00 |
| E-032 | Measurement | Bun tests: 2 pass, 0 fail | bun test .../verify-toolchain.test.ts |
Bun 1.3.6 |
| E-033 | Measurement | npm registry snapshot для versioned alternatives | npm view <package> version |
2026-07-25 |
Version snapshot#
Версии ниже — snapshot registry на дату исследования, не обещание автоматического upgrade:
| Категория | Кандидат | Точная версия |
|---|---|---|
| Compiler/types | typescript / @types/node |
7.0.2 / 24.13.3 |
| Schema | ajv / zod |
8.20.0 / 4.4.3 |
| Property tests | fast-check |
4.9.0 |
| State/rules | xstate / json-rules-engine |
5.32.5 / 7.3.1 |
| Graph | graphology / @dagrejs/graphlib |
0.26.0 / 4.0.1 |
| Event store | @eventstore/db-client |
6.2.1 |
| Telemetry/eval | @opentelemetry/sdk-node / langsmith / braintrust |
0.221.0 / 0.8.7 / 3.24.0 |
| Provider SDK | openai / @anthropic-ai/sdk / @google/genai |
6.49.0 / 0.115.0 / 2.13.0 |
Decision matrix#
| Область | Кандидаты | Решение для prototype | Почему сейчас | Trigger для пересмотра | Evidence |
|---|---|---|---|---|---|
| Runtime | Node 24.14.0; Bun 1.3.6 | Node primary; Bun smoke | Оба исполнили один erasable .ts; Node — authoritative target |
Bun станет supported production runtime | E-003–E-005, E-030, E-031 |
| Package manager | npm 11.9.0; Bun installer | npm only | package-lock.json уже authoritative; Bun installer создаст второй lock |
Отдельное одобренное migration решение | E-005, E-008, E-009 |
| Compiler | TypeScript 7.0.2 | Select | Strict check необходим независимо от runtime stripping | Compiler regression или нужен stable programmatic API | E-003, E-006, E-007, E-028 |
| Schema validation | Ajv 8.20.0; Zod 4.4.3 | Ajv select; Zod reject as primary | JSON Schema можно разделить с provider/tool contracts; повторная runtime validation остаётся обязательной | Internal-only domain model перестанет иметь JSON Schema boundary | E-010, E-022, E-024, E-026 |
| Authoritative transitions | Native typed pure reducers; XState 5.32.5; json-rules-engine 7.3.1 | Native reducers select | Минимальная deterministic/replay поверхность; rules остаются кодом и проходят review | Statechart lifecycle реально станет сложным либо появится host-configurable policy DSL | E-012, E-013 |
| Invariant testing | Example tests; fast-check 4.9.0 | fast-check select | Подходит для reducer/replay/map invariants и shrinking | Только fixed fixtures без combinatorial state space | E-011 |
| Graph model | Native Map/Set; Graphology 0.26.0; Graphlib 4.0.1 |
Native first; libraries defer | Малый map/reachability не оправдывает dependency | Нужны weighted algorithms, large graph, serialization interop или multigraph | E-014, E-015 |
| Local event persistence | Memory/JSONL; node:sqlite; external event store |
Append-only memory/JSONL for R&D | Достаточно для deterministic replay; сохраняет Bun lane | Crash durability, concurrent writers или query workload | E-017 |
| Production event store | Postgres append-only table; Kurrent/EventStore client 6.2.1 | No selection | Сервисная нагрузка и durability contract ещё не измерены; исследованный client legacy | Есть SLO, concurrency/load test и migration plan | E-016 |
| Tracing | Local JSONL; OTel 0.221.0; Phoenix | Local JSONL now; OTel interface candidate | Нулевой внешний сервис и provider-neutral поля | Появится multi-process path или distributed latency investigation | E-018, E-021 |
| Eval platform | Local deterministic scorers; LangSmith 0.8.7; Braintrust 3.24.0 | Local scorer first; managed tools defer | Нет paid calls/dataset/privacy decision | Есть versioned eval dataset, budget и data policy | E-019, E-020 |
| Structured output | OpenAI, Anthropic, Gemini contracts | Provider adapter + shared JSON Schema + Ajv revalidation | Все имеют schema ограничения; schema validity не равна game-rule validity | После выбора провайдера выполнить contract tests на разрешённых models | E-022, E-024, E-026 |
| Prompt caching | OpenAI automatic prefix; Anthropic prefix/breakpoints; Gemini implicit/explicit | Adapter metrics only; provider deferred | Semantics/usage counters различаются; без paid calls hit rate неизвестен | Разрешён replayable cost/latency benchmark | E-023, E-025, E-026 |
Журнал экспериментов#
| Время | Изменение или попытка | Наблюдение | Artifact или evidence ID | Вывод |
|---|---|---|---|---|
| 2026-07-25T01:05+07:00 | Test написан до verifier | Exit 1, ожидаемый missing module | E-027 |
RED подтверждён |
| 2026-07-25T01:08+07:00 | Реализован metadata evaluator и CLI | Strict typecheck exit 0 | E-028 |
Erasable/strict subset компилируется |
| 2026-07-25T01:08+07:00 | Node unit + CLI | 2/2 tests; 13/13 findings ok |
E-029, E-030 |
H-01 и H-03 подтверждены |
| 2026-07-25T01:08+07:00 | Bun CLI над тем же файлом | 13/13 findings ok; второго lock нет |
E-031 |
H-02 подтверждена в измеренном scope |
| 2026-07-25T01:10+07:00 | Bun test runner | 2/2 tests | E-032 |
Pure evaluator совместим и с Bun test lane |
Выводы#
- Measurement: один
.tsentry point прошёл strict compiler gate и выполнился в Node 24.14.0 и Bun 1.3.6. Основание:E-028–E-032. - Inference: один lockfile совместим с двумя runtime только потому, что
installer остаётся один — npm. Это policy constraint, а не функция
синхронизации двух package managers. Основание:
E-005,E-008,E-031. - Inference: authoritative game state лучше начать с pure reducer, а
XState/rules engine подключать по доказанному усложнению. Основание:
E-012,E-013. - Inference: provider structured output должен проходить Ajv и затем
domain reducer validation; provider guarantee не доказывает допустимость
команды в текущем game state. Основание:
E-010,E-022,E-024,E-026.
Рассмотренные альтернативы#
| Подход | Что проверили | Почему не выбран | Evidence |
|---|---|---|---|
| Bun как installer рядом с npm | Официальный migration/lock contract | Создаёт bun.lock, нарушая критерий одного lockfile |
E-005 |
Runtime без tsc |
Node/Bun TS execution contract | Type stripping/transpilation не проверяет типы | E-003, E-004 |
| XState для всех transitions | Возможности statechart/actors | Дополнительная semantic layer не нужна для малого deterministic kernel | E-012 |
| JSON rules для core mechanics | JSON conditions/facts | Слабее reviewability/type exhaustiveness для authoritative reducer | E-013 |
| Graph library с первого дня | Graphology/Graphlib APIs | Native adjacency достаточно для текущего маленького graph | E-014, E-015 |
| Managed eval platform сейчас | LangSmith/Braintrust contracts | Нет разрешённого paid dataset run, privacy/budget decision | E-019, E-020 |
| Provider SDK в prototype | Три structured-output/cache контракта | Provider ещё не выбран; SDK не нужен для локального доказательства | E-022–E-026 |
Неизвестные#
- Unknown: совместимость полного будущего dependency graph с Bun. Закрыть полным Bun smoke после появления integrated vertical slice.
- Unknown: Linux/CI reproducibility. Закрыть чистым
npm ciи теми же четырьмя командами на CI runner. - Unknown: production event-store throughput/durability. Закрыть после формулировки SLO и concurrent-writer benchmark.
- Unknown: model quality, latency, price и provider cache-hit rate. Закрыть только разрешённым versioned benchmark с сохранёнными usage records.