Expand description
wasmtime-бекенд wit/*.wit-контрактів (n7n:fix-deps@0.1.0) — спека
2026-08-17-n7n-harness-local-models.md, §3.12 пункт 16, ДРУГА половина
(пункт 16а — контракти й in-process-бекенд, harness::registry — уже
зроблений, без wasmtime; цей крейт додає ЄДИНУ нову залежність, яку
той крок свідомо не чіпав).
§Чому окремий крейт, а не harness/llm-lib
wasmtime — найбільша залежність усього плану FixDeps-плагінів.
harness тримає інваріант «нуль важких залежностей» (CI перевіряє
cargo tree -p n7n-harness --all-features — там немає wasmtime); і
n7n-llm-lib (featureless-ядро) щойно спеціально звужували (§3.1).
Обидва інваріанти цей крейт не чіпає — він лише СПОЖИВАЄ обидва
(n7n-harness за типами DetectFn/T0Fn/Violation/VerifyFn/
AstFactsFn з crate::registry/crate::pipeline, n7n-llm-lib з
default-features = false за EditPlan/FileEditPlan/VerifyReport).
Підключає його лише той споживач, що реально вантажить wasm-плагіни
(rules-fix) — harness/llm-lib лишаються придатними для
споживачів, яким wasm не потрібен, без жодного зайвого байта в графі.
§Що тут головне: чотири Wasm* — друга реалізація тих самих слотів
harness::registry::PluginRegistry уже спроєктований так, що бекенд
компонента — друга реалізація T усередині Slot<T>, не окремий
трейт-об’єкт (доккоментар registry.rs, “чому T, а не трейт”). Чотири
типи нижче — WasmDetector, WasmVerify, WasmAstFacts,
WasmT0 — виробляють РІВНО ті самі callable-типи, що in-process
бекенд уже приймає (harness::pipeline::DetectFn,
harness::registry::VerifyFn, harness::registry::AstFactsFn,
harness::pipeline::T0Fn) — PluginRegistry::new/replace_* не
відрізняє, звідки прийшло замикання: з Arc::new(|| ...) напряму чи
з WasmDetector::into_detect_fn() нижче. Володіння (реєстр, Slot,
generation, LIFO-аквайр) лишається рівно тим самим кодом
(crates/harness/src/registry.rs) — цей крейт лише постачає ЩО саме
кладеться в слот.
§Безпекова межа (§3.9) — де вона виражена в коді
- Guest-и не отримують WASI-права запису взагалі. Єдине місце, де
guest отримує (чи не отримує) права на диск — [
wasi_ctx::read_only_repo_ctx]:DirPerms::READ/FilePerms::READ, нульMUTATEв усьому крейті. Кожен із чотирьохWasm*::call*нижче будуєWasiCtxРІВНО через цю функцію — підміни в обхід неї немає, боStoreдля guest-виклику ніде більше в крейті не конструюється. - T0 повертає
edit-plan, хост застосовує.WasmT0::into_t0_fnвиробляє лишеharness::pipeline::T0Fn(порахувати план) — фаза застосування (PreparePlanFn/CommitPlanFn,write_guard) сюди НЕ входить:n7n-llm-libтут узятий зdefault-features = false, тожwrite_guard(живе під фічеюagents) цьому крейту недоступний за побудовою — той самий принцип, що вже застосовуєharness::registry(доккоментарT0Step: “prepare/commit— цілком хостові… не частина контракту «порахувати план»”). Викликач збирає повнийT0Step { plan: wasm_t0.into_t0_fn(), prepare: ..., commit: ... }сам, як і сьогодні для in-process T0. - Жодного спавну процесів у guest. Жоден із чотирьох
wit/*.witworld-ів не імпортує нічого, що дало б guest-у спавнити процес (жодногоwasi:cli/exec-подібного імпорту в жодному зdetector-plugin/verify-plugin/ast-facts-plugin/t0-plugin), і WASI Preview 2 в принципі не має такого стандартного інтерфейсу — немає wasi-фічі, яку можна було б увімкнути, щоб це з’явилось. - Інстанс на спробу, без кешу. Кожен
Wasm*::call*будує СВІЖИЙStore+WasiCtx+Instanceна КОЖЕН виклик (не лише на коженcheckout()реєстру) — суворіша гарантія, ніж вимагає §3.16 правило 3 (“інстанс на спробу”): жодного способу випадково закешуватиInstanceміж викликами немає, бо для нього просто немає поля, яке пережило б виклик. Кешується лише СКОМПІЛЬОВАНИЙwasmtime::component::Component(іEngine/Linker, які самі по собі не несуть стану guest-а) — те саме розрізнення “Component ≠ Instance”, яке задача явно вимагає.
§Тестовий guest
tests/guest/detector_fixture і tests/guest/t0_fixture — мінімальні
wasm32-wasip2-компоненти для наскрізного тесту
(tests/wasmtime_backend.rs). Компіляція гейтована наявністю
wasm32-wasip2 в rustup target list --installed — де його немає
(чи cargo build для guest-крейта впаде з іншої причини, напр. немає
мережі до crates.io), тест друкує причину й виходить РАНО, не падаючи:
середовище цієї задачі мало і target, і мережу (перевірено на старті),
тож тут наскрізний прогін ДІЙСНО виконується, а не лише компілюється
бекенд.
Structs§
- Wasm
AstFacts - Wasm-бекенд одного
ast-facts-компонента — доккоментарcrate::detector::WasmDetector. - Wasm
Detector - Wasm-бекенд одного
detector-компонента: скомпільованийComponent/Engine/Linker— кешовані (доккоментар crate-level “інстанс на спробу, без кешу” — кешується лише СКОМПІЛЬОВАНИЙ компонент, неInstance), плюс корінь репозиторію для read-only preopen-у. - WasmT0
- Wasm-бекенд одного
t0-компонента — доккоментарcrate::detector::WasmDetector. - Wasm
Verify - Wasm-бекенд одного
verify-компонента — доккоментарcrate::detector::WasmDetectorпояснює кешуванняComponent/Engine/Linkerпроти “інстанс на спробу” дляInstance.