<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">Собрать Hello VibeVM на AI-Native Rust</title>
  <status stage="doc" state="work" audience="user"/>
  <p p="1">Эта страница превращает калькулятор со страницы [Создать первый проект](../start/first-project.xml) в программу на Rust. Заодно она связывает каждое записанное правило калькулятора с кодом, который его соблюдает, и с тестом, который это доказывает. Связь даёт AI-Native Rust — дисциплина, которую вы добавляете в проект так же, как добавили redbook. Код остаётся обычным Rust. Строгость уходит вокруг него: в типы, в ошибки, которые называют нарушенное правило, и в проверки, которые выполняет машина. Заложите около часа; на долю агента придётся меньше десяти минут.</p>
  <section id="what-you-need" title="Что понадобится">
    <table p="2">
      <tr>
        <td>Что</td>
        <td>Зачем</td>
        <td>Где взять</td>
      </tr>
      <tr>
        <td>проект `hello-vibevm` с его [спецификацией](../glossary/index.xml#specification)</td>
        <td>по ней эта страница собирает программу</td>
        <td>[Создать первый проект](../start/first-project.xml)</td>
      </tr>
      <tr>
        <td>Rust и `cargo-nextest`</td>
        <td>компилирует программу и прогоняет проверки дисциплины</td>
        <td>шаг 1 ниже</td>
      </tr>
      <tr>
        <td>агент-кодер</td>
        <td>пишет программу вместе с вами</td>
        <td>тот же, что на первой странице</td>
      </tr>
      <tr>
        <td>около 3 ГБ свободного места на диске</td>
        <td>для инструментов Rust и инструментов дисциплины</td>
        <td></td>
      </tr>
    </table>
  </section>
  <section id="install-rust" title="Шаг 1: установить Rust">
    <p p="3">Если терминал уже отвечает на `cargo --version`, переходите к последней части этого шага. Иначе поставьте Rust через rustup, официальный установщик. Он кладёт в домашнюю папку компилятор, сборщик `cargo`, форматтер и линтер.</p>
    <section id="on-windows" title="В Windows">
      <p p="4">1. Скачайте `rustup-init.exe` с [rustup.rs](https://rustup.rs), сборку для x64 или для ARM64, и запустите его.</p>
      <p p="5">2. Если он сообщит, что нет инструментов сборки C++ из Visual Studio, разрешите ему их поставить. Rust в Windows пользуется их компоновщиком.</p>
      <p p="6">3. Согласитесь на установку по умолчанию, затем откройте новый терминал.</p>
    </section>
    <section id="on-macos" title="В macOS">
      <p p="7">1. Поставьте инструменты командной строки Apple, в которых есть компоновщик:</p>
      <fence lang="shell" p="8">xcode-select --install</fence>
      <p p="9">2. Поставьте Rust и согласитесь на установку по умолчанию:</p>
      <fence lang="shell" p="10">curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh</fence>
      <p p="11">3. Откройте новый терминал.</p>
    </section>
    <section id="on-linux" title="В Linux">
      <p p="12">1. Поставьте компилятор C пакетным менеджером вашего дистрибутива: `sudo apt install build-essential` в Debian и Ubuntu, `sudo dnf install gcc` в Fedora.</p>
      <p p="13">2. Поставьте Rust той же командой, что и в macOS, и согласитесь на установку по умолчанию:</p>
      <fence lang="shell" p="14">curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh</fence>
      <p p="15">3. Откройте новый терминал.</p>
    </section>
    <section id="check-rust" title="Проверить и добавить один инструмент">
      <p p="16">1. Убедитесь, что обе команды печатают версию:</p>
      <fence lang="shell" p="17">rustc --version
cargo --version</fence>
      <p p="18">2. Поставьте `cargo-nextest`, программу запуска тестов, которую вызывает последняя проверка дисциплины. Она собирается из исходников, это займёт несколько минут:</p>
      <fence lang="shell" p="19">cargo install cargo-nextest --locked</fence>
      <p p="20">Форматтер `rustfmt` и линтер `clippy` пришли вместе с установкой по умолчанию. Позже всё это обновляет `rustup update`.</p>
    </section>
  </section>
  <section id="add-the-discipline" title="Шаг 2: добавить AI-Native Rust в проект">
    <p p="21">AI-Native Rust — [семейство](../glossary/index.xml#family) из трёх пакетов, и оно приводит с собой четвёртый. Ставите вы бандл, `rust-ai-native`. Его языковой пакет держит руководство по Rust в этой дисциплине и инструменты, которые её проверяют. Его [MCP-сервер](../glossary/index.xml#mcp-server) открывает эти инструменты агентам. Четвёртый пакет, `core-ai-native`, содержит ядро дисциплины, одно для всех языков.</p>
    <p p="22">Две фразы ядра объясняют остальное. Первая говорит, куда уходит строгость: вокруг кода, а не в его синтаксис.</p>
    <rule ref="spec://org.vibevm.ai-native/core-ai-native/00-MANIFESTO#CENTRAL-LAW" p="23"/>
    <p p="24">Вторая говорит, что считается строгостью. Правило, которое могло бы стать проверкой, тестом или типом, но записано фразой, ещё не существует.</p>
    <rule ref="spec://org.vibevm.ai-native/core-ai-native/00-MANIFESTO#PROSE-IS-A-WISH" p="25"/>
    <p p="26">Дальше работайте внутри папки проекта.</p>
    <p p="27">1. Поставьте семейство:</p>
    <fence lang="shell" p="28">cd hello-vibevm
vibe install org.vibevm.ai-native/rust-ai-native --assume-yes</fence>
    <p p="29">2. Соберите его инструменты. Пакеты несут исходный код, и vibe компилирует программы на вашей машине, внутри папок самих пакетов:</p>
    <fence lang="shell" p="30">vibe bin build --assume-yes</fence>
    <p p="31">Первая сборка идёт от полуминуты до нескольких минут. Она оставляет в этих папках около 370 мегабайт результатов сборки, и Git их не отслеживает.</p>
    <p p="32">3. Посмотрите, что пришло. `vibe tree` показывает семейство рядом с redbook. `vibe tools` перечисляет шесть инструментов: пять программ и сервер. Вызывать вы будете один из них, `rust-ai-native`. Он настраивает проект, строит [карту прослеживаемости](../glossary/index.xml#traceability-map) от правил к коду и запускает все проверки разом. Вызывайте его через vibe, который находит сборку, принадлежащую этому проекту: `vibe bin exec rust-ai-native -- &lt;команда&gt;`.</p>
    <p p="33">4. Закоммитьте:</p>
    <fence lang="shell" p="34">git add -A
git commit -m "chore: add AI-Native Rust"</fence>
    <p p="35">[Стартовая полоса](../glossary/index.xml#boot-lane) теперь называет ещё два текста, и агент читает их в начале каждой сессии. Они повторяют две фразы выше и добавляют постоянные правила для Rust. Значение, которое пересекает границу, получает собственный тип. У каждого слоя один тип ошибки, и его сообщения ссылаются на правило, которое он охраняет. Логика программы не вызывает `unwrap`. Каждая публичная точка входа несёт скомпилированный пример использования.</p>
  </section>
  <section id="traceable" title="Шаг 3: сделать спецификацию прослеживаемой">
    <p p="36">Дисциплина строит свою карту, читая вашу [спецификацию](../glossary/index.xml#specification). О каждом правиле ей нужно знать две вещи: какого оно вида и какая его ревизия текущая. Обе помещаются в одну короткую пометку, строку вида. Ставьте её отдельной строкой, первой под заголовком правила:</p>
    <fence lang="markdown" p="37">## Деление на ноль {#division-by-zero}

`req r1`

Деление на ноль считается ошибкой. Программа печатает
`error: division by zero` в поток ошибок и выходит с кодом 1.</fence>
    <p p="38">1. Откройте `vibevm/vibespecs/modules/calculator/PROP-001.md`. Под заголовком каждого правила поставьте `` `req r1` ``: ввод, числа, операторы, результат, деление на ноль и неверный ввод.</p>
    <p p="39">2. Под заголовком каждого из двух решений поставьте `` `design r1` ``.</p>
    <p p="40">3. В `FEAT-001.md` поставьте `` `design r1` `` под заголовком границ и `` `req r1` `` под заголовком приёмки. Между строкой вида и таблицей оставьте пустую строку.</p>
    <p p="41">4. Не меняйте ни одного [якоря](../glossary/index.xml#anchor). Когда на следующем шаге дисциплина будет настроена, её инструменты будут находить каждое правило по адресу. Адрес складывается из имени проекта, пути документа под `vibevm/vibespecs/` и якоря: `spec://hello-vibevm/modules/calculator/PROP-001#division-by-zero`.</p>
    <p p="42">5. Закоммитьте:</p>
    <fence lang="shell" p="43">git add vibevm/vibespecs/modules
git commit -m "docs(calculator): mark the rules and their revisions"</fence>
    <p p="44">Ревизия понадобится вам в конце страницы. Когда смысл правила меняется, вы поднимаете её номер. Тогда каждый кусок кода и каждый тест, который ссылался на старую ревизию, становится подозрительным, пока кто-нибудь его не перечитает.</p>
    <rule ref="spec://org.vibevm.ai-native/core-ai-native/mechanisms/PROP-014#INVALIDATION-SPEC-BUMP-MAKES-EDGES-SUSPECT" p="45"/>
  </section>
  <section id="build" title="Шаг 4: попросить агента собрать программу">
    <p p="46">Запустите агента в `hello-vibevm`, как на первой странице, и дайте ему этот запрос:</p>
    <prompt id="hello-build" p="47">
      Собери Hello VibeVM по его спецификации как AI-Native Rust, следуя руководству, которое установил этот проект: библиотека с тонким бинарником, правила спецификации в виде типов, ошибки со ссылкой на нарушенное правило, doctest на каждом публичном элементе и таблица приёмки как одна объявленная матрица тестов. Привяжи каждый элемент к его правилу и закончи зелёным rust-ai-native floor.
      <needs>сессия агента, запущенная в `hello-vibevm` после установки AI-Native Rust; Rust с `cargo-nextest`</needs>
      <outcome>библиотека с тонким бинарником; `cargo run -q -- "7 / 2"` печатает `3.5`; у каждого публичного элемента есть doctest и привязка к его правилу; `rust-ai-native floor` показывает все проверки зелёными</outcome>
      <assert>test "$(cargo run -q -- "7 / 2")" = "3.5"</assert>
      <assert>cargo test --quiet</assert>
      <assert>vibe bin exec rust-ai-native -- floor</assert>
    </prompt>
    <p p="48">Запрос называет суть нарочно. Проверки дисциплины читают форму кода. Маленькая аккуратная программа проходит их раньше, чем хоть одно правило спецификации поселится в её типах.</p>
    <p p="49">В первый раз эту страницу проверяли запросом, который просил только зелёных проверок. Агент написал правильный Rust и привязал каждую функцию к её правилу. Но оператор остался строкой, а числом считалось любое значение с плавающей точкой. Руководство это запрещает, но ни одна проверка пока не следит за этим правилом:</p>
    <rule ref="spec://org.vibevm.ai-native/rust-ai-native-lang/rust/GUIDE-AI-NATIVE-RUST#BAN-STRINGLY-TYPED-SURFACES" p="50"/>
    <p p="51">Поэтому запрос просит того, чего машина не выведет сама: где проходят границы программы и какие правила должны стать типами.</p>
    <p p="52">Будьте готовы, что агент сначала читает, а потом пишет. В проверочном прогоне его первые пятьдесят действий были чтением. Он прочитал стартовую полосу, руководство дисциплины и три её карточки. Он прочитал даже исходники инструментов, которые собирался запускать.</p>
    <p p="53">Потом он написал крейт за один заход и настроил дисциплину командой `rust-ai-native init`. Он сразу поставил крейт под все проверки, а не освободил от них. Шаг занял около семи минут и закончился двумя коммитами: сначала калькулятор, затем настройки дисциплины и карта. Агент может заново собрать инструменты; вреда от этого нет.</p>
    <p p="54">Прочитайте последнее сообщение агента. В проверочном прогоне он перечислил решения, которые принял там, где спецификация молчит. Ещё он назвал то, что оставил вам, например лицензию проекта.</p>
  </section>
  <section id="read-it" title="Шаг 5: прочитать, что он собрал">
    <p p="55">Зелёные проверки говорят, что ничего не сломано. Они не говорят, что спецификация стала кодом. Вместо них посмотрите на пять вещей.</p>
    <p p="56">1. Прогоните программу по таблице приёмки и за её пределами. `cargo run -q -- "7 / 2"` печатает `3.5`. `cargo run -q -- "1 / 0"` печатает `error: division by zero` и выходит с кодом 1. Теперь попробуйте `"nan + 1"`, ввод, которого в таблице нет. Программа печатает ``error: `nan` is not a number`` и выходит с кодом 2, потому что по спецификации число записывается десятичной дробью.</p>
    <p p="57">2. Найдите типы. Агент написал пять небольших модулей вокруг одной мысли: значение, которое нарушает правило, не может существовать. Число можно получить только из текста, который подходит под грамматику спецификации, поэтому `NaN` и бесконечность внутрь не попадут. Оператор стал типом ровно с четырьмя значениями, так что «и никаких других» теперь проверяет компилятор. Выражение можно получить только разбором. Даже коды выхода стали типом с тремя значениями, теми тремя, что разрешает спецификация.</p>
    <p p="58">3. Найдите тип ошибки. У него два лица. Для вас это короткое описание проблемы, которое программа печатает после `error: ` теми словами, какими его задаёт спецификация. Для агента это полная диагностика, которая называет нарушенное правило и место, где его чинить:</p>
    <fence lang="text" p="59">violates REQ spec://hello-vibevm/modules/calculator/PROP-001#division-by-zero: division by zero; fix surface: divide by a number other than zero</fence>
    <rule ref="spec://org.vibevm.ai-native/rust-ai-native-lang/rust/GUIDE-AI-NATIVE-RUST#ERROR-MESSAGES-ARE-AGENT-FOOD" p="60"/>
    <p p="61">4. Найдите тесты. Таблица приёмки из `FEAT-001.md` встречается в коде один раз: списком строк, которые прогоняются против собранной программы. У каждого публичного элемента в документации есть короткий пример, и `cargo test` компилирует и запускает его. В проверочном прогоне таких примеров было 23 из 33 тестов.</p>
    <p p="62">5. Спросите карту, какой код соблюдает правило и какой тест это доказывает:</p>
    <fence lang="shell" p="63">vibe explain "spec://hello-vibevm/modules/calculator/PROP-001#division-by-zero"</fence>
    <fence lang="text" p="64">spec unit spec://hello-vibevm/modules/calculator/PROP-001#division-by-zero
  req r1 — Division by zero (vibevm/vibespecs/modules/calculator/PROP-001.md:25)
  hash sha256:b0c1fd84b983…
  edges in:
    implements ← `hello_vibevm::error::CalcError` (crates/hello-vibevm/src/error.rs:35) (pinned r1)
    implements ← `hello_vibevm::error::CalcError::exit_status` (crates/hello-vibevm/src/error.rs:194) (pinned r1)
    implements ← `hello_vibevm::operator::Operator::apply` (crates/hello-vibevm/src/operator.rs:55) (pinned r1)
    verifies ← `hello_vibevm::operator::tests::dividing_by_either_zero_is_an_error` (crates/hello-vibevm/src/operator.rs:136) (pinned r1)</fence>
    <p p="65">Там, где спецификация молчит, агент выбрал осторожный ответ и пометил его `REVIEW` в коде. В проверочном прогоне таких мест было три: ведущий `+`, числа вроде `.5` и результат, слишком большой, чтобы его хранить. Отвечайте на них по одному, как советует первая страница. Крейт вышел примерно на 1100 строк. Большая часть из них приходится на оболочку: документацию, примеры, привязки и тесты. Сама арифметика занимает десяток строк.</p>
  </section>
  <section id="change-a-rule" title="Шаг 6: изменить правило и увидеть, что связь держится">
    <p p="66">1. В `PROP-001.md` замените сообщение о делении на ноль на `error: cannot divide by zero`. Поднимите строку вида этого правила до `` `req r2` ``.</p>
    <p p="67">2. В `FEAT-001.md` замените то же сообщение в таблице приёмки и поднимите ту строку вида до `` `req r2` ``. Закоммитьте оба файла.</p>
    <p p="68">3. Спросите карту, чего коснулась правка. Проверка падает и перечисляет каждый элемент, который ссылался на старую ревизию:</p>
    <fence lang="shell" p="69">vibe bin exec rust-ai-native -- specmap --check</fence>
    <fence lang="text" p="70">Error: `.\specmap.json` is out of date relative to the tree.
  drift: revision bump: `spec://hello-vibevm/modules/calculator/FEAT-001#acceptance` r1 → r2
  drift:   now SUSPECT: `hello_vibevm::tests::acceptance::feat_001_acceptance_table` (pinned r1) at crates/hello-vibevm/tests/acceptance.rs:88 — re-affirm after review
  drift: revision bump: `spec://hello-vibevm/modules/calculator/PROP-001#division-by-zero` r1 → r2
  drift:   now SUSPECT: `hello_vibevm::error::CalcError` (pinned r1) at crates/hello-vibevm/src/error.rs:35 — re-affirm after review
  drift:   now SUSPECT: `hello_vibevm::error::CalcError::exit_status` (pinned r1) at crates/hello-vibevm/src/error.rs:194 — re-affirm after review
  drift:   now SUSPECT: `hello_vibevm::operator::Operator::apply` (pinned r1) at crates/hello-vibevm/src/operator.rs:55 — re-affirm after review
  drift:   now SUSPECT: `hello_vibevm::operator::tests::dividing_by_either_zero_is_an_error` (pinned r1) at crates/hello-vibevm/src/operator.rs:136 — re-affirm after review
Run `rust-ai-native-specmap` (or your project's wrapper), review the drift, and commit the result.</fence>
    <p p="71">4. Дайте агенту этот запрос:</p>
    <prompt id="hello-rule-change" p="72">
      Правила division-by-zero и acceptance теперь в ревизии r2. Приведи каждый элемент, который на них ссылается, в соответствие с новым текстом и подтверди их заново. Закончи зелёным rust-ai-native floor.
      <needs>сессия агента из шага 4 или новая, запущенная в `hello-vibevm`</needs>
      <outcome>программа печатает новое сообщение; карта не называет ни одного подозрительного элемента; `rust-ai-native floor` зелёный</outcome>
      <assert>test "$(cargo run -q -- "1 / 0" 2&gt;&amp;1)" = "error: cannot divide by zero"</assert>
      <assert>vibe bin exec rust-ai-native -- floor</assert>
    </prompt>
    <p p="73">В проверочном прогоне агент сначала прочитал правку и список. Потом он поменял восемь строк в трёх файлах, меньше чем за минуту. Три строки несли сообщение: в коде, в примере, который его проверяет, и в строке таблицы. Остальные пять были привязками, подтверждёнными в ревизии `r2`. Ради этой петли дисциплина и существует. Вы поменяли фразу, и код и тесты, которые от неё зависели, нашла машина, а не чья-то память.</p>
    <p p="74">Карта находит то, что привязано к правилу, и только это. В проверочном прогоне один комментарий в другом файле так и повторял старые слова, потому что его ничто не связывало с правилом. Агент его оставил: комментарий описывал ошибку, а не цитировал вывод. Привязывайте элемент к правилу везде, где иначе фразу пришлось бы помнить.</p>
  </section>
  <section id="what-appeared" title="Что появилось на диске">
    <p p="75">Рядом со спецификацией в проекте теперь лежит код на Rust. Наверху стоит `Cargo.toml`, а крейт лежит в `crates/hello-vibevm/`. Калькулятор находится в `src/lib.rs` и его модулях, тонкая программа в `src/main.rs`, тесты приёмки в `tests/`. Ещё агент добавил `/target/` в `.gitignore`, чтобы результаты сборки Rust не попадали в Git.</p>
    <p p="76">`conform.toml` и `specmap.toml` держат политику дисциплины и настройки карты; их правите вы. `specmap.json` и есть сама карта. Она сгенерирована и закоммичена, поэтому ревьюер видит в диффе, когда меняются привязки правила. `conform-baseline.json` и файлы в `discipline/registry/` хранят записи самих проверок. Здесь они пустые, то есть никаких поблажек нет.</p>
  </section>
  <section id="edge-cases" title="Особые случаи и правила">
    <p p="77">Берите выражение в кавычки в любой оболочке. Без кавычек Git Bash в Windows превращает одинокий `/` в путь, а оболочка превращает `*` в имена файлов.</p>
    <p p="78">Не приписывайте строку вида к тексту: пусть она стоит одна. Если поставить её перед списком, первый пункт списка станет обычным текстом.</p>
    <p p="79">Спецификация, которую писал агент, может ссылаться на свои правила как `spec://project/…`. Это адрес проекта до того, как дисциплина дала ему имя; после шага 4 адреса начинаются с `spec://hello-vibevm/`. Замените старое начало в обоих файлах, иначе эти ссылки никуда не ведут.</p>
    <p p="80">После всего, что сдвигает строки в коде, включая форматирование, пересоберите карту командой `vibe bin exec rust-ai-native -- specmap` и только потом запускайте `floor`. Карта помнит номера строк, и устаревшая карта проваливает проверку.</p>
    <p p="81">Когда `floor` останавливается на карте и предполагает свежий проект, карта всего лишь устарела. `specmap --check` покажет почему. Сдвинутым строкам хватит пересборки; поднятая ревизия требует ревью из шага 6.</p>
    <p p="82">В Windows Git может выписать `specmap.json` с окончаниями строк CRLF. Тогда проверка карты падает как устаревшая и не называет никакого дрейфа. Добавьте строку `specmap.json text eol=lf` в `.gitattributes` проекта, закоммитьте её и один раз пересоберите карту.</p>
    <p p="83">Каждая сборка карты предупреждает о `vibevm/vibespecs/boot/STATIC.xml`. Карта читает всё под `vibevm/vibespecs/`, включая сгенерированную стартовую полосу. Чтобы исключить полосу, добавьте `spec_exclude = ["vibevm/vibespecs/boot/**"]` в `specmap.toml` выше первой строки `[[external_specs]]`. Затем пересоберите карту.</p>
    <p p="84">Если `floor` останавливается на последнем шаге и называет `cargo-nextest`, значит, нет программы запуска тестов. Поставьте её, как показывает шаг 1.</p>
  </section>
</spec>
