# 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-совместимости. ## Метод 1. Зафиксировать версии локального runtime/toolchain и корневых manifest/lock. 2. Проверить официальные контракты Node, Bun, TypeScript и npm. 3. До реализации создать regression tests для npm-only invariants и получить RED из-за отсутствующего verifier. 4. Реализовать один erasable-syntax TypeScript verifier только на `node:` built-ins. 5. Выполнить strict typecheck, tests под Node и Bun, затем по одному CLI-запуску verifier в каждом runtime. 6. Сопоставить текущие версии библиотек с минимальными потребностями прототипа. Сетевые 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](https://nodejs.org/docs/latest-v24.x/api/typescript.html) | accessed 2026-07-25; Node 24 | | E-004 | Fact | Bun напрямую запускает TypeScript и поддерживает Node-style resolution | [Bun TypeScript runtime](https://bun.sh/docs/runtime/typescript), [module resolution](https://bun.sh/docs/runtime/module-resolution) | accessed 2026-07-25; Bun 1.3.6 | | E-005 | Fact | `bun install` импортирует npm lock и создаёт `bun.lock`; поэтому он не входит в выбранный workflow | [Bun lockfiles](https://bun.sh/docs/pm/lockfile), [migration from npm](https://bun.sh/docs/guides/install/from-npm-install-to-bun-install) | accessed 2026-07-25; Bun 1.3 | | E-006 | Fact | `strict` включает семейство строгих type checks; NodeNext моделирует современный Node ESM/CJS contract | [TS strict](https://www.typescriptlang.org/tsconfig/strict.html), [TS module](https://www.typescriptlang.org/tsconfig/module.html#nodenext) | accessed 2026-07-25; TypeScript 7.0.2 | | E-007 | Fact | TypeScript 7.0 использует новый compiler, но сохраняет `tsc` CLI; stable compiler API ещё не является основанием решения | [TypeScript 7.0 announcement](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/) | accessed 2026-07-25; TypeScript 7.0 | | E-008 | Fact | npm lockfile описывает точное дерево установки и предназначен для commit в source repository | [npm package-lock docs](https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/) | 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](https://ajv.js.org/guide/typescript.html), [Ajv options](https://ajv.js.org/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](https://fast-check.dev/docs/introduction/what-is-property-based-testing/) | accessed 2026-07-25; fast-check 4.9.0 | | E-012 | Fact | XState предоставляет actors/statecharts для сложных lifecycle | [XState docs](https://stately.ai/docs/xstate) | 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](https://github.com/CacheControl/json-rules-engine) | accessed 2026-07-25; 7.3.1 | | E-014 | Fact | Graphology — graph structure с сериализацией и отдельной standard library алгоритмов | [Graphology docs](https://graphology.github.io/) | accessed 2026-07-25; 0.26.0 | | E-015 | Fact | Graphlib реализует directed/undirected multigraph и базовые graph algorithms | [Graphlib repository](https://github.com/dagrejs/graphlib) | 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](https://docs.kurrent.io/clients/node/legacy/v6.2/appending-events) | 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](https://nodejs.org/download/release/latest-v24.x/docs/api/sqlite.html) | accessed 2026-07-25; Node 24 | | E-018 | Fact | OpenTelemetry JS: traces/metrics stable, logs ещё development | [OpenTelemetry JS](https://opentelemetry.io/docs/languages/js/), [instrumentation](https://opentelemetry.io/docs/languages/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](https://docs.langchain.com/langsmith/evaluation-types) | accessed 2026-07-25; LangSmith 0.8.7 | | E-020 | Fact | Braintrust CLI может запускать local evaluation без отправки logs; managed upload остаётся отдельным выбором | [Braintrust evaluation docs](https://www.braintrust.dev/docs/evaluate/run-evaluations) | accessed 2026-07-25; Braintrust 3.24.0 | | E-021 | Fact | Phoenix принимает OpenTelemetry traces и предлагает self-hosted tracing/evals/datasets | [Phoenix docs](https://arize.com/docs/phoenix) | accessed 2026-07-25; service/protocol candidate | | E-022 | Fact | OpenAI Structured Outputs ограничивают output JSON Schema; application semantic validation всё равно требуется | [OpenAI Structured Outputs](https://developers.openai.com/api/docs/guides/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](https://developers.openai.com/api/docs/guides/prompt-caching) | accessed 2026-07-25 | | E-024 | Fact | Anthropic предоставляет JSON outputs/strict tool use с ограниченным JSON Schema contract | [Anthropic structured outputs](https://platform.claude.com/docs/en/build-with-claude/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](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) | accessed 2026-07-25 | | E-026 | Fact | Gemini structured output поддерживает subset JSON Schema и требует отдельной semantic validation; caching бывает implicit/explicit | [Gemini structured output](https://ai.google.dev/gemini-api/docs/structured-output), [context caching](https://ai.google.dev/gemini-api/docs/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 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:** один `.ts` entry 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.