DigitableCourses

Formal Type Surface · open source

Бизнес-правило, которое можно прочитать, выполнить и проверить.

FTS — отступный язык исполняемых спецификаций. Вы описываете предметные данные, правила и примеры без скобок; один .fts становится работающей утилитой, тестами, TypeScript-кодом, UI-описанием или проверяемым допуском команды. А с языком flang тот же файл печатается исходником на JavaScript, C, Go, Rust или Python — и на нём же переписано само ядро FTS.

232
прикладных кейса
23
модулей курса
2
языка записи
5
языков печати
0
runtime-зависимостей
discount.fts
категория «Продажи»

  объект Покупка
    сумма является деньгами

  утилита «Рассчитать скидку»
    принимает Покупка
    возвращает деньги
    начинает с 0

    правило «Большая покупка»
      если сумма не меньше 10000
      и сумма не больше 100000
      то добавить 10 процентов от поля сумма

    пример «Двадцать тысяч»
      дано сумма равна 20000
      ожидается результат равен 2000
✓ fts test1/1 passed

Зачем ещё один язык

Он убирает разрыв между фразой в задаче и кодом в проде.

Обычная спецификация объясняет намерение, а реализация живёт отдельно. FTS делает проверяемую часть правила единым исходником для людей, приложения, тестов и агентов.

  1. 01Пишем предметное правилоНа русском или английском, с отступами и читаемыми именами.
  2. 02Компилятор строит модельПроверяет типы, поля, ссылки, композицию и примеры.
  3. 03Выбираем выходИсполнить, тестировать, сгенерировать TS, форму, таблицу или сертификат.
  4. 04Хост выполняет эффектNode, React, Python, CI или агент используют один канонический JSON-контракт.
Граница честности

FTS хорошо описывает чистые вычисления и проверяемые допуски. Он не генерирует оплату, SQL-транзакцию или HTTP-вызов: приложение выполняет внешний эффект только после результата FTS.

Одна модель — разные уровни работы

Что получает каждый разработчик.

Junior

Описывает данные и примеры

Пишет структуру формы или таблицы и проверяет ожидаемые результаты как новые предметные unit-тесты.

fts test order.fts
Middle

Встраивает утилиту

Вызывает FTS из Node.js или генерирует TypeScript, оставляя HTTP, БД и очереди в обычном коде.

fts generate order.fts
Senior

Фиксирует инварианты

Отделяет чистую бизнес-политику от эффектов, вводит command guards, свойства и версионируемые контракты.

fts certify policy.fts
Lead

Синхронизирует язык команды

Связывает DDD-контекст, код, CI и архитектурные решения одним проверяемым артефактом.

fts pipeline domain.fts
AI agent

Предлагает, но не решает сам

Агент пишет FTS и вызывает MCP. Компилятор, тесты и verifier принимают детерминированное решение.

fts_verify → verified

Один смысл · две записи

Русский и English без скобок.

Обе поверхности исполняются одним парсером и нормализуются в одну каноническую модель. Имена с пробелами пишутся в кавычках; обычные кавычки и «ёлочки» поддерживаются.

discount.ru.fts
категория «Продажи»

  объект Покупка
    сумма является деньгами
    «постоянный клиент» является признаком

  утилита «Рассчитать скидку»
    принимает Покупка
    возвращает деньги
    начинает с 0

    правило «Большая покупка»
      если сумма не меньше 10000
      и сумма не больше 100000
      то добавить 10 процентов от поля сумма

    свойство «Скидка ограничена»
      результат не больше 15000

    пример «Покупка на двадцать тысяч»
      дано сумма равна 20000
      дано «постоянный клиент» равен нет
      ожидается результат равен 2000

Живая песочница

Отредактируйте правило — результат пересчитается в вашей вкладке.

Здесь работает тот же компилятор @digitable/fts, что и в Node.js: разбор, предметные примеры, выполнение утилиты, генерация TypeScript и доказательство теоремы считаются локально, без единого запроса на сервер.

order-discount.fts

Компилятор загрузится, когда секция появится на экране.

Компилятор загружается…

Интеграция

FTS не заменяет React, Node.js или Python. Он отдаёт им проверенное решение.

Node.jsИсполнить напрямую
import { compile, executeUtility } from "@digitable/fts"

const model = compile(source)
const discount = executeUtility(
  model,
  "Рассчитать скидку",
  { сумма: 20_000, "постоянный клиент": true }
)

Node отвечает за HTTP и базу; FTS — только за детерминированное правило.

ReactПолучить форму
import { compile } from "@digitable/fts/browser"
import { FtsForm } from "@digitable-lol/ui-components"

const document = compile(source)
return <FtsForm
  document={document}
  objectName="Покупка"
  value={value}
  onChange={setValue}
/>

Компонент берёт поля из той же модели, которую проверяет backend.

Любой языкГраница через JSON
fts run discount.fts \
  --utility "Рассчитать скидку" \
  --input purchase.json

# stdout: JSON
# failure: non-zero exit code

Python, Go, Java, Rust и shell используют CLI или каноническую JSON-схему.

AI / DigitПроверить до действия
fts_check
fts_test
fts_execute
fts_certify
fts_verify  # status must be verified

Модель может написать текст, но допуск consequential-команды решает verifier.

FTS вырос в язык · flang

Спецификация не описывает код проекта — она в него печатается.

Документ, описывающий правило, расходится с реализацией в тот же день, когда его согласовали, и узнают об этом на проде. Поэтому правило здесь не документ: тот самый .fts, который открыт в песочнице выше, исполняется как раньше — и печатается готовым исходником на JavaScript, C, Go, Rust или Python, который ложится в репозиторий проекта и даёт те же значения, те же коды и те же тексты ошибок, что интерпретатор.

Печатает его flang — полный язык, выросший из FTS: суммы типов, коллекции, строки как данные, рекурсия и сопоставление с образцом. Любая модель FTS остаётся валидной программой flang, поэтому переход ничего не ломает: ниже одно и то же правило и его свойство в пяти целевых языках.

order-discount.fts · тот же файл, что открыт в песочницеисходник
    правило «Очень крупная покупка»
      если сумма больше 100000
      то добавить 15000

    свойство «Скидка ограничена»
      результат не больше 15000
prodazhi.js · хвост функции «Рассчитать скидку»flang emit order-discount.fts --target js
  let $t6
  if ($cond($gt($field(vhod, "сумма"), 100000))) {
    $t6 = $add(rezultat2, 15000)
  } else {
    $t6 = rezultat2
  }
  const rezultat3 = $t6
  // постусловие «Скидка ограничена»
  if (!$post($lte(rezultat3, 15000), "Скидка ограничена", "Рассчитать скидку")) {
    $fail("FTS_UTILITY_PROPERTY", "нарушено свойство «Скидка ограничена» утилиты «Рассчитать скидку»")
  }
  return rezultat3
}
prodazhi.c · хвост функции «Рассчитать скидку»flang emit order-discount.fts --target c
  fl_value fl_t26 = fl_nothing();
  FL_TRY(fl_field_get(ctx, vhod, "сумма", &fl_t26, error));
  fl_value fl_t27 = fl_nothing();
  FL_TRY(fl_gt(ctx, fl_t26, fl_number(100000.0), &fl_t27, error));
  bool fl_t28 = false;
  FL_TRY(fl_cond(ctx, fl_t27, &fl_t28, error));
  fl_value fl_t29 = fl_nothing();
  if (fl_t28) {
    fl_value fl_t30 = fl_nothing();
    FL_TRY(fl_add(ctx, rezultat2, fl_number(15000.0), &fl_t30, error));
    fl_t29 = fl_t30;
  } else {
    fl_t29 = rezultat2;
  }
  const fl_value rezultat3 = fl_t29; /* пусть «результат3» */
  (void)rezultat3;
  const fl_value fl_t31 = rezultat3;
  fl_value fl_t32 = fl_nothing();
  FL_TRY(fl_lte(ctx, fl_t31, fl_number(15000.0), &fl_t32, error));
  /* постусловие «Скидка ограничена» */
  bool fl_t33 = false;
  FL_TRY(fl_post(ctx, fl_t32, "Скидка ограничена", "Рассчитать скидку", &fl_t33, error));
  if (!fl_t33) {
    return fl_fail(ctx, error, "FTS_UTILITY_PROPERTY", "%s", "нарушено свойство «Скидка ограничена» утилиты «Рассчитать скидку»");
  }
  *result = fl_t31;
  return FL_OK;
}
prodazhi.go · хвост функции «Рассчитать скидку»flang emit order-discount.fts --target go
	t46, e47 := rt.FieldGet(ctx, vhod, "сумма")
	if e47 != nil {
		return rt.Value{}, e47
	}
	t48, e49 := rt.Gt(ctx, t46, rt.Number(100000.0))
	if e49 != nil {
		return rt.Value{}, e49
	}
	t50, e51 := rt.Cond(ctx, t48)
	if e51 != nil {
		return rt.Value{}, e51
	}
	var t52 rt.Value
	if t50 {
		t53, e54 := rt.Add(ctx, rezultat2, rt.Number(15000.0))
		if e54 != nil {
			return rt.Value{}, e54
		}
		t52 = t53
	} else {
		t52 = rezultat2
	}
	// пусть «результат3»
	rezultat3 := t52
	_ = rezultat3
	t55 := rezultat3
	t56, e57 := rt.Lte(ctx, t55, rt.Number(15000.0))
	if e57 != nil {
		return rt.Value{}, e57
	}
	// постусловие «Скидка ограничена»
	t58, e59 := rt.Post(ctx, t56, "Скидка ограничена", "Рассчитать скидку")
	if e59 != nil {
		return rt.Value{}, e59
	}
	if !t58 {
		return rt.Value{}, rt.Fail("FTS_UTILITY_PROPERTY", "%s", "нарушено свойство «Скидка ограничена» утилиты «Рассчитать скидку»")
	}
	return t55, nil
}
prodazhi.rs · хвост функции «Рассчитать скидку»flang emit order-discount.fts --target rust
    let t26 = rt::field_get(ctx, vhod.clone(), "сумма")?;
    let t27 = rt::gt(ctx, t26, rt::number(100000.0))?;
    let t28 = rt::cond(ctx, t27)?;
    let t29 = if t28 {
        let t30 = rt::add(ctx, rezultat2.clone(), rt::number(15000.0))?;
        t30
    } else {
        rezultat2.clone()
    };
    // пусть «результат3»
    let rezultat3 = t29;
    let t31 = rezultat3.clone();
    // постусловие «Скидка ограничена»
    let t32 = rt::lte(ctx, t31.clone(), rt::number(15000.0))?;
    let t33 = rt::post(ctx, t32, "Скидка ограничена", "Рассчитать скидку")?;
    if !t33 {
        return Err(rt::fail("FTS_UTILITY_PROPERTY", "нарушено свойство «Скидка ограничена» утилиты «Рассчитать скидку»".to_string()));
    }
    Ok(t31)
}
prodazhi.py · хвост функции «Рассчитать скидку»flang emit order-discount.fts --target python
    if rt.cond(ctx, rt.gt(ctx, rt.field_get(ctx, vhod, "сумма"), rt.number(100000.0))):
        _t6 = rt.add(ctx, rezultat2, rt.number(15000.0))
    else:
        _t6 = rezultat2
    # пусть «результат3»
    rezultat3 = _t6
    _t7 = rezultat3
    # постусловие «Скидка ограничена»
    if not rt.post(ctx, rt.lte(ctx, _t7, rt.number(15000.0)), "Скидка ограничена", "Рассчитать скидку"):
        raise rt.fail("FTS_UTILITY_PROPERTY", "нарушено свойство «Скидка ограничена» утилиты «Рассчитать скидку»")
    return _t7

Фрагменты напечатаны командой flang emit static/fts/models/order-discount.fts --target js|c|go|rust|python — это вывод компилятора, а не пересказ. Показан хвост одной функции: последнее правило и постусловие. Свойство «Скидка ограничена» — не комментарий и не тест рядом: в каждом языке это исполняемая проверка с кодом FTS_UTILITY_PROPERTY. Напечатанный модуль самодостаточен, рантайм печатается в тот же каталог. Собранный C, собранный Rust, напечатанные JavaScript и Python на входе «сумма 20000, постоянный клиент да» отвечают 3000 — ровно столько же, сколько считает песочница выше.

flang emit

Пять целевых языков

JavaScript, C, Go, Rust и Python. Каждый бэкенд сверен с интерпретатором дифференциально: 31 программа, 154 функции, 2235 входов — совпадают значения, коды и тексты ошибок.

node --test flang/test/emit-*.test.mjs
flang/core

Ядро FTS переписано на flang

Лексер, парсер, вычислитель и печать JSON — 300 функций, и все тотальные. Цепочка текст → JSON байт в байт совпадает с эталонным ядром на TypeScript на всём корпусе моделей: и репозитория языка, и этого портала.

текст → лексер → парсер → JSON
без Node

Ядро собирается в нативный бинарник

Ядро печатается в C и собирается cc -Werror -pedantic без единого предупреждения. В зависимостях только libc и libm: ни Node, ни пакетов, ни виртуальной машины.

flang emit core/parser.flang --target c
тотальная

Два класса программ

Завершение тотальной функции доказывает компилятор, а не комментарий рядом. Только такие годятся для факт-чекинга: то, что обязано ответить «подтверждено или нет», не имеет права зависнуть.

FLANG_NOT_TOTAL
LeetCode

Годится не только для правил

26 решений на flang: список, число, рекурсия и ни одной предметной области — и та же доказанная завершаемость, что у бизнес-правила.

flang/examples/leetcode/
Почему не раньше

Ограничение записано в самом FTS — tools/ftsc/self/meta.fts: «в ядре FTS строка является типом поля, но не значением, над которым можно вычислять». Парсер — это вычисления над строками, поэтому написать ядро FTS на самом FTS было нельзя. flang снял ровно это ограничение, и первым, что на нём написали, стало ядро FTS.

Что находится при переносе

Мы перенесли расчёт корзины с lodash на модель. Тест сравнил обе версии и нашёл три дефекта.

Не «код стал чище»: правило получило свойства и примеры, и 350 входов прошли через обе реализации. Совпало 317, разошлось 33 — каждое расхождение оказалось ошибкой старого кода. Пример целиком лежит в репозитории: examples/fts/lodash.

clampМолча обрезал скидку

Золотой статус, опт и промокод давали 14 % при пределе 13 %. clamp возвращал потолок, и на цене 1234.55 клиент получал скидку 1604.92 — число, которого не описывает ни одно правило.

14 из 350 входовFTS_UTILITY_PROPERTY
roundОкруглял дважды

Округление стояло внутри каждого слагаемого. База 157.50: 7 % = 11.025 и 5 % = 7.875, обе половинки копейки уходили вверх. Итог 18.91 вместо 18.90 — правым оказался расчёт по модели.

19 из 350 входовкопейка на каждой позиции
defaultToПрятал отсутствие цены

Позиция без цены давала итог 0: clamp(NaN, 0, NaN) возвращает нижнюю границу, а defaultTo добивает остаток. Корзина с неоценённым товаром выглядела правдоподобно. Модель останавливается на типе входа.

тихий 0 вместо отказаFTS_UTILITY_INPUT_TYPE
Граница честности

Полного порта lodash не будет: в языке нет коллекций и функций высшего порядка, поэтому map, filter, groupBy, debounce и cloneDeep остаются в JavaScript и переезжать не должны. В модель уходит другая половина вызовов — та, что на самом деле была бизнес-правилом без проверки.

Разбор целиком — в главе курса «Вам не нужен lodash — но не там, где вы думаете».

Реальные проекты

Четыре рабочих проекта и готовый CI: сервис, допуск команды, кодогенерация, форма.

Это не псевдокод из слайдов. Файлы лежат в репозитории курса, покрыты тестами и запускаются одной командой: npm run fts:examples. Ниже — их настоящее содержимое.

Скидка как HTTP-сервис

Node.js отвечает за сокет и коды ответа, FTS — за правило. Примеры модели выполняются на старте: если предметный тест не проходит, сервис не поднимается.

Запуск
npm run fts:api
Проверка
node --test examples/fts/discount-api/server.test.mjs
examples/fts/discount-api/server.mjs
/**
 * HTTP-сервис расчёта скидки поверх FTS.
 *
 * Разделение ответственности, ради которого всё и затевалось:
 *   — FTS отвечает за бизнес-правило (какая скидка положена);
 *   — Node.js отвечает за эффекты (сокет, маршруты, коды ответа, лимит тела).
 *
 * Примеры из модели выполняются на старте: если предметный тест не проходит,
 * сервис не поднимается вообще. Правило, которое не проходит собственные
 * примеры, до продакшена не доезжает.
 *
 * Запуск:  node examples/fts/discount-api/server.mjs
 * Проверка: curl -s localhost:8788/discount -d '{"сумма":20000,"постоянный клиент":true}'
 */
import { createServer } from 'node:http';
import { readFile } from 'node:fs/promises';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { resolve } from 'node:path';

import { assertValid, compile, executeUtility, testUtilities } from '../../../static/js/vendor/fts/browser.js';

const here = fileURLToPath(new URL('.', import.meta.url));
export const MODEL_FILE = resolve(here, '../../../static/fts/models/order-discount.fts');
const UTILITY = 'Рассчитать скидку';
const MAX_BODY = 64 * 1024;

export async function createCalculator(modelFile = MODEL_FILE) {
  const document = assertValid(compile(await readFile(modelFile, 'utf8')));
  const tests = testUtilities(document);
  if (!tests.valid) {
    const failed = tests.results.filter((result) => !result.passed);
    throw new Error(
      `FTS-примеры не прошли (${failed.length} из ${tests.total}): ` +
        failed.map((result) => `«${result.example}» ожидалось ${result.expected}, получено ${result.actual}`).join('; '),
    );
  }
  return { document, tests, calculate: (purchase) => executeUtility(document, UTILITY, purchase) };
}

export async function createDiscountServer(modelFile = MODEL_FILE) {
  const { calculate, tests, document } = await createCalculator(modelFile);
  const fields = document.structures.find((structure) => structure.name === 'Покупка').fields;

  return createServer(async (request, response) => {
    try {
      if (request.method === 'GET' && request.url === '/health') {
        return send(response, 200, { ok: true, model: document.category, examples: `${tests.passed}/${tests.total}` });
      }
      if (request.method === 'GET' && request.url === '/contract') {
        return send(response, 200, { utility: UTILITY, input: fields, output: 'Деньги' });
      }
      if (request.method !== 'POST' || request.url !== '/discount') {
        return send(response, 404, { error: 'используйте POST /discount' });
      }
      const purchase = JSON.parse(await readBody(request));
      return send(response, 200, { discount: calculate(purchase) });
    } catch (error) {
      /* Нарушенное свойство и неизвестное поле — это ошибка запроса, а не сбой
         сервиса: клиенту возвращается причина, диагностика FTS не теряется. */
      return send(response, 400, {
        error: error instanceof Error ? error.message : String(error),
        diagnostics: error?.diagnostics ?? [],
      });
    }
  });
}

async function readBody(request) {
  const chunks = [];
  let size = 0;
  for await (const chunk of request) {
    size += chunk.length;
    if (size > MAX_BODY) throw new Error('тело запроса больше 64 КБ');
    chunks.push(chunk);
  }
  return Buffer.concat(chunks).toString('utf8');
}

function send(response, status, body) {
  response.writeHead(status, { 'content-type': 'application/json; charset=utf-8' });
  response.end(`${JSON.stringify(body, null, 2)}\n`);
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  const port = Number.parseInt(process.env.FTS_HTTP_PORT ?? '8788', 10);
  const server = await createDiscountServer();
  server.listen(port, '127.0.0.1', () => {
    process.stdout.write(`Discount API: http://127.0.0.1:${port} (POST /discount, GET /contract, GET /health)\n`);
  });
}
Ответ на неверный тип входа400 · FTS_UTILITY_INPUT_TYPEне 500

Каталог применимости

232 real-world кейса: вход → FTS → результат.

Это не 232 обещаний «можно автоматизировать». Каждый кейс называет входные факты, роль FTS, выходной артефакт и место интеграции.

Показано 24 из 232
РитейлMiddle

Рассчитать скидку корзины

Retail: deterministic calculation

  1. ВходСумма корзины, сегмент и промокод
  2. FTSСложить применимые проценты и проверить верхний предел
  3. На выходеЧисловая скидка без скрытых веток
Node.jsFTS runtimeTypeScriptnode:test
РитейлSenior

Разрешить возврат товара

Retail: command eligibility

  1. ВходПокупка, срок и состояние товара
  2. FTSВывести право на возврат из проверяемых фактов
  3. На выходеКоманда «Оформить возврат» разрешена или отклонена
DDDcommand guardcertificateJSON
РитейлQA / Middle

Проверить бесплатную доставку

Retail: executable examples

  1. ВходСумма, регион и вес
  2. FTSВыполнить примеры на границах тарифа
  3. На выходеРегрессия тарифа блокирует сборку
CI/CDfts testpropertyCI gate
РитейлJunior

Собрать форму товарной карточки

Retail: generated form

  1. ВходСтруктура товара и обязательность полей
  2. FTSСкомпилировать поля в каноническую модель
  3. На выходеОписание React-формы
Reactcanonical JSONform descriptorReact
РитейлJunior / Middle

Собрать таблицу остатков

Retail: generated table

  1. ВходSKU, склад, остаток и резерв
  2. FTSПревратить типы полей в колонки
  3. На выходеКонфигурация таблицы без ручного дублирования
React / Webcanonical JSONtable columnsfrontend
РитейлSenior / Lead

Доказать готовность заказа к выдаче

Retail: verified transition

  1. ВходОплата и факт комплектации
  2. FTSСкомпозировать состояния в разрешение выдачи
  3. На выходеПроверяемый сертификат перехода
ArchitecturemorphismcertificateMermaid
РитейлAI agent

Дать агенту расчёт цены

Retail: agent tool

  1. ВходЗапрос покупателя и снимок корзины
  2. FTSВызвать детерминированную FTS-утилиту через MCP
  3. На выходеСтруктурированный ответ с диагностикой
Digit / MCPMCPstructured resultdiagnostics
РитейлTeam

Защитить правила промокодов

Retail: regression gate

  1. ВходНабор граничных примеров
  2. FTSЗапустить примеры и свойства в CI
  3. На выходеНенулевой exit code при расхождении
CI/CDgenerated testsexit codebuild gate
МаркетплейсыMiddle

Рассчитать комиссию продавца

Marketplaces: deterministic calculation

  1. ВходКатегория, оборот и тариф
  2. FTSПрименить последовательность комиссионных правил
  3. На выходеСумма комиссии и сгенерированный тест
Node.jsFTS runtimeTypeScriptnode:test
МаркетплейсыSenior

Разрешить публикацию товара

Marketplaces: command eligibility

  1. ВходКарточка, документы и ограничения
  2. FTSПроверить свидетельства допуска
  3. На выходеКоманда публикации с объяснимым guard
DDDcommand guardcertificateJSON
МаркетплейсыQA / Middle

Проверить SLA отгрузки

Marketplaces: executable examples

  1. ВходДедлайн, статус и схема FBO/FBS
  2. FTSЗафиксировать примеры нарушения SLA
  3. На выходеВоспроизводимый тест бизнес-сроков
CI/CDfts testpropertyCI gate
МаркетплейсыJunior

Собрать форму нового SKU

Marketplaces: generated form

  1. ВходАтрибуты категории товара
  2. FTSПолучить поля из одной структуры FTS
  3. На выходеДинамическая форма кабинета
Reactcanonical JSONform descriptorReact
МаркетплейсыJunior / Middle

Собрать таблицу выплат

Marketplaces: generated table

  1. ВходПериод, продажи, удержания, итог
  2. FTSСопоставить типы с форматтерами колонок
  3. На выходеТаблица сверки выплат
React / Webcanonical JSONtable columnsfrontend
МаркетплейсыSenior / Lead

Доказать право на выплату

Marketplaces: verified transition

  1. ВходДоставка, период спора и KYC
  2. FTSСвязать факты морфизмами допуска
  3. На выходеСертификат разрешения выплаты
ArchitecturemorphismcertificateMermaid
МаркетплейсыAI agent

Дать агенту проверку листинга

Marketplaces: agent tool

  1. ВходТекст карточки и факты продавца
  2. FTSПередать исходник в fts_check и fts_execute
  3. На выходеРешение агента, ограниченное валидатором
Digit / MCPMCPstructured resultdiagnostics
МаркетплейсыTeam

Защитить сетку комиссий

Marketplaces: regression gate

  1. ВходПримеры по категориям и порогам
  2. FTSГенерировать node:test из FTS
  3. На выходеСтабильный релиз тарификации
CI/CDgenerated testsexit codebuild gate
БанкингMiddle

Рассчитать кредитный лимит

Banking: deterministic calculation

  1. ВходДоход, нагрузка и риск-класс
  2. FTSВычислить лимит и проверить максимум
  3. На выходеДетерминированный лимит
Node.jsFTS runtimeTypeScriptnode:test
БанкингSenior

Разрешить выдачу кредита

Banking: command eligibility

  1. ВходKYC, скоринг и риск-проверка
  2. FTSСкомпозировать свидетельства допуска
  3. На выходеGuard команды выдачи
DDDcommand guardcertificateJSON
БанкингQA / Middle

Проверить пороги скоринга

Banking: executable examples

  1. ВходГраничные баллы и ожидаемые классы
  2. FTSИсполнить предметные примеры
  3. На выходеТесты скоринговой политики
CI/CDfts testpropertyCI gate
БанкингJunior

Собрать форму заявки

Banking: generated form

  1. ВходПоля клиента и финансов
  2. FTSСкомпилировать структуру заявки
  3. На выходеReact-форма с типами
Reactcanonical JSONform descriptorReact
БанкингJunior / Middle

Собрать таблицу просрочек

Banking: generated table

  1. ВходДоговор, DPD и остаток долга
  2. FTSПолучить колонки из структуры
  3. На выходеОперационная таблица коллекшна
React / Webcanonical JSONtable columnsfrontend
БанкингSenior / Lead

Доказать допустимость операции

Banking: verified transition

  1. ВходЛимит, санкционный контроль и MFA
  2. FTSПровести типизированную цепочку морфизмов
  3. На выходеПроверяемый сертификат операции
ArchitecturemorphismcertificateMermaid
БанкингAI agent

Дать агенту pre-check заявки

Banking: agent tool

  1. ВходАнкета без сетевых секретов
  2. FTSВызвать read-only MCP-инструменты FTS
  3. На выходеСтруктурированный pre-check
Digit / MCPMCPstructured resultdiagnostics
БанкингTeam

Защитить риск-политику

Banking: regression gate

  1. ВходНабор одобренных и отказных заявок
  2. FTSПроверить свойства и примеры в CI
  3. На выходеЗапрет мержа при изменении решения
CI/CDgenerated testsexit codebuild gate

Цена интеграции

FTS-проход измеряется миллисекундами, но общий build нужно мерить в вашем проекте.

Baseline: Apple M1 Max, Node.js 24.6.0. Это microbenchmark рантайма FTS, а не обещание времени Vite, webpack или полного tsc.

Операция10 элементов1001000
Compile0.0511 ms0.3937 ms4.3608 ms
Validate0.0102 ms0.0883 ms1.0154 ms
Execute0.0010 ms0.0021 ms0.0157 ms
Generate TypeScript0.0065 ms0.0392 ms0.3704 ms
Transpile generated TS1.8410 ms3.6606 ms22.9837 ms

При масштабе 1000 compile + validate занимает около 5.38 ms на этой машине. В курсе есть воспроизводимый harness и методика сравнения before/after.

Новый полный курс

От первого правила до production-интеграции и проверяемых сертификатов.

23 последовательных модулей: синтаксис, утилиты, новые unit-тесты, диагностика компилятора, Node.js, React, DDD, миграция легаси, версии правил, AI/MCP, CI, benchmark и научные границы доказательства. В каждом модуле — упражнения, которые выполняются прямо в песочнице.

  1. Язык и модель
  2. Утилиты и тесты
  3. Интеграции
  4. DDD и агенты
  5. Proofs и benchmark
Открыть курс