Repository navigation
Releases: KUARU-dotcom/Lupus
Release list
Lupus V0.6.0
Lupus V0.6.0 — семантика, GC, сеть, асинхронность, встраивание
BREAKING CHANGES (от 0.5.x)
and/orвозвращают значение (схема Scheme), а не только булево.()— литерал пустого списка, а неnone.head/tail/nth/empty?/contains?/lengthна неверном типе →
type-mismatch(ранее местами молчаливоеnone).- Конструкторы
defstructпроверяют конкретные типы полей.
Подробности: docs/ERRATA.md §13, раздел BREAKING CHANGES V0.6.
Новое
- GC: conservative mark-and-sweep разрывает циклы
env → контейнер → closure → env (#47): утечка 17.1 МиБ → 80 Б в тесте;
пауза 8.3 мс на 20k живых замыканий;(gc-collect); порогLUPUS_GC_THRESHOLD. - texas (сеть, §3.3): tcp/udp, все ошибки — значения
(failure "net: …"),
таймауты чтения 5 с. - lappland:
(lappland/malice p),(lappland/delay k)— инъекция отказов
и задержек для сетевых вызовов; детерминизм черезLUPUS_MALICE_SEED. - amiya (async, §3.5): spawn/channel/send/recv/recv-timeout/wait/wait-all;
snapshot-семантика spawn; Socket/Listener/Task не маршалируются. - kennel (host-API): профили pure/core/full,
Host::register_native,
run_program; host-нативы под префиксомhost/. - fuel (#35, #36): лимит шагов
LUPUS_FUEL=N/Config.max_steps;
(set-fuel! n)только уменьшает потолок; исчерпание →exhausted. - eval --import w,senko "" — пре-импорт пакетов в REPL-режиме.
- Семантика: политика типов унифицирована, проверки конструкторов (ERRATA §13).
Метрики
- 285 тестов; golden 46 / negative 136; LiF 3/3.
- Fuzz 10 000 программ (20 000 в CI): 0 паник, 0 таймаутов.
- Oracle-дифференциал против v0.4.0: 118 файлов, 94 pass / 0 fail / 24 skip.
- fib(25): медиана 309 мс (перф-гейт 315 мс в CI).
- Коды ошибок: +profile-denied, fuel-raise-denied, exhausted, host-error.
Бинарники
Linux x86_64 + Windows x86_64 (macOS не поставляется: нужен osxcross).
Разработка
Архитектура: Qwen3.8 Max / Qwen3.7 Max. Код: DeepSeek V4.1 Flash (OpenCode).
Аудит: агентская сеть «NikoGPT» (DeepSeek V4.1 Flash).
Lupus V0.5.3
Release Notes — Lupus V0.5.3
Дата: 2026-10-28
Тег: v0.5.3
Коммит: см. тег v0.5.3
Что нового
Утечка памяти в кэше модулей закрыта (#45)
Определение функции через lambda в одном процессе теряло память: цепочка
окружение → замыкание → окружение образовывала Rc-цикл, который не
разбирался при выходе. На CLI это было не видно (процесс живёт один запуск),
но Interpreter — публичный API библиотеки, и хост, крутящий много коротких
скриптов в одном процессе, тёк на каждое определение.
Замер: 20 000 прогонов одного и того же исходника в одном процессе.
| Сценарий | До | После |
|---|---|---|
(+ 1 2) (контроль) |
+0.2 МБ | +0.2 МБ |
(import fnmod) (fnmod/inc 1) |
+21 МБ | +0.2 МБ |
(define f (lambda (x) (+ x 1))) (f 1) |
+21 МБ | +0.2 МБ |
Закреплено тестом tests/memory.rs, который проверяет именно разрыв цикла
через Weak::upgrade(), а не размер RSS — флака не будет.
Встроенные функции стали значениями
Раньше (list-map (list 1 -2) abs) падало с «Переменная 'abs' не определена»:
встроенные функции не были значениями. Теперь они первоклассные:
(list-map (list 1 -2) abs) ; → (1 2)
(define f head) (f (list 1 2)) ; → (some 1)
(import senko) (define root senko/sqrt) (root 81.0) ; → 9.0Добавлены list-filter и list-fold. Внутри таблица builtins заменила
матч на ~300 строк.
Runtime-ошибки теперь с позицией
Ошибки, возникшие при вычислении узла AST, больше не имеют location = null:
{"phase":"runtime","code":"type-mismatch","message":"+ требует чисел",
"location":{"file":"/tmp/loc.lupus","line":2,"col":1,
"span":{"start":13,"end":22}}}Это расширение схемы §6.1. location = null остаётся только там, где ошибка
не привязана к исходнику: io-error до разбора, отказ spawn,
no-tests-found.
Фаззинг
В репозитории появилась фаззинг-инфраструктура: cargo-fuzz с таргетами
parse_eval и lexer, workflow по расписанию каждые 6 часов, затравка
корпуса из tests/golden и examples, сохранение артефактов, автосоздание
issue при находке. Первые прогоны: lexer — 2.4 млн исполнений на cov: 747,
parse_eval — 293 тыс. на cov: 3649, падений нет.
Breaking changes от V0.5.2
locationв runtime-ошибках. Кто парсит JSON по схеме §6.1 и ожидает
location = nullдляruntime, увидит объект. Изменение расширяющее, но
поведение другое.- Ошибки без кода больше не классифицируются по тексту. Удалён
Error::new/infer_code; код ошибки теперь всегда задаётся явно. На
пользователя не влияет, на сторонниеuse lupus::error::Error— влияет.
Известные ограничения
- #47: фикс #45 закрывает циклы
окружение → замыкание → окружение, но
не циклы через контейнеры (окружение → список → замыкание → окружение).
(define-mutable l (list)) (set! l (append l (list (lambda () 1))))течёт
по-прежнему. Списки, накапливающие лямбды в глобальной переменной, —
основной риск для встраивания (kennel, V0.6). Полное решение требует GC
или обхода значения приdefine/set!. - #35 / #36: в интерпретаторе нет лимита вычислительных шагов (fuel).
Скрипт с бесконечным циклом подвешивает процесс — для встраивания в чужой
хост это неприемлемо. Планируетсяfuel-exhaustedв V0.6. - HM-тайпчекер не реализован (V1.0). Аннотации типов проверяются
синтаксически. - Tensor (
exusiai) отложен в V2.0. - macOS-сборка не поставляется (нужен Apple SDK).
Метрики
| Метрика | V0.5.2 | V0.5.3 | Δ |
|---|---|---|---|
| Тестов cargo | 217 | 231 | +14 |
| Кодов ошибок | 32 | 32 | 0 |
Линий в interpreter.rs |
~1420 | ~715 | −50% |
| Утечка на 20k определений | +21 МБ | +0.2 МБ | −99% |
Установка
wget https://github.com/KUARU-dotcom/Lupus/releases/download/v0.5.3/lupus-v0.5.3-linux-x86_64.tar.gz
tar xzf lupus-v0.5.3-linux-x86_64.tar.gz
./lupus --versionИз исходников:
git clone https://github.com/KUARU-dotcom/Lupus.git
cd Lupus && cargo build --release
./target/release/lupus --versionРазработка
- Архитектура и спецификация: Qwen3.8 Max / Qwen3.7 Max
- Реализация: DeepSeek V4.1 Flash
- Аудит и фаззинг: NikoGPT (github.com/nikogpt-bot; мультимодельная
агентская платформа, аудит выполнен на DeepSeek V4.1 Flash 1017) —
фаззинг-инфраструктура, обнаружение утечки #45, триаж ложных находок
Документация
Lupus V0.5.2
Lupus V0.5.2 — патч-релиз по дельта-аудиту
Закрыто (находки дельта-аудита NikoGPT к v0.5.1):
- #33 (major): комбинирующие знаки (Mn/Mc) допустимы в продолжении идентификатора
(NFD-café,ко́феработают); знак первым символом — по-прежнему unknown-token;
NFC-нормализация источника отложена в V1.0. - #31 (major): любая usage-ошибка CLI (нет позиционного аргумента, лишние
позиционные, флаг без команды, голый вызов) → exit 2 + usage в stderr,
stdout пустой, JSON нет.--help/-hостался успешным путём (rc 0). - #34 (minor):
-<буква>трактуется как неизвестный флаг (exit 2), а не как имя
файла;-<цифра>и одиночный-остались позиционными. - #32 (minor): число с буквенным хвостом (
1a) → lex-ошибка unknown-token
с позицией вместо молчаливого разбиения на два токена.
Тестов: 217. Гейты: clippy/fmt чисто, validate_tasks 100/100, LiF 3/3,
fuzz 10 000 программ / 0 паник, oracle (обязательный режим) 109 файлов /
93 pass / 0 fail. ERRATA: §12.
Бинарники: Linux x86_64 + Windows x86_64 (macOS не поставляется: нужен osxcross).
Lupus V0.5.1
Lupus V0.5.1 — патч-релиз
Закрыто по аудиту NikoGPT (issues #23–#30, BUG-40, BUG-41):
- #24:
lupus testбез тестов → exit 1, кодno-tests-found - #30: симлинки больше не дублируют прогоны (canonicalize + без следования по симлинкам)
- #25: BOM в начале файла пропускается
- #26: колонки в диагностике — в символах, не в UTF-8 байтах
- #27: суррогатные пары
\uXXXXсобираются в scalar; одинокий суррогат →invalid-escape - #29: неизвестные escape → ошибка
invalid-escapeс позицией - #28: неизвестный CLI-флаг → exit 2 + plain-text usage (не ошибка языка)
- BUG-41: отказ spawn потока → JSON
io-error, без паники - BUG-40: README — раздел «Бенчмарк», пути results/, базовая линия merged-lupus-2bv2
- #23: Unicode-идентификаторы (кириллица и др. alphabetic); emoji по-прежнему unknown-token
- Docs: семантика захвата в циклах (while — позднее связывание, for — значение итерации),
ERRATA §10 - ERRATA:
/в символьном токене (qualified-имена семантически идентичны)
Тестов: 204 (+6). Гейты: clippy/fmt чисто, validate_tasks 100/100,
fuzz 10 000 программ / 0 паник, oracle 107 файлов / 92 pass / 0 fail.
Бинарники: Linux x86_64 + Windows x86_64. macOS не поставляется (требует osxcross).
Lupus V0.5.0
Release Notes — Lupus V0.5.0
Дата: 2026-10-25
Тег: v0.5.0
Коммит: 68d186c
Что нового
Модульная система
(import senko),(import kaltsit),(import w)— нативные пакеты в Rust- Префиксы:
senko/pi,kaltsit/read-file,w/assert-eq - Модификаторы
:asи:all(:allпод линтомimport-collision) - Файловые модули с кэшем загрузки (исполняются ровно один раз)
- Детекция циклических импортов (
import-cycle) - Env-переменная
LUPUS_PATHдля пользовательских каталогов модулей
Нативная стандартная библиотека (Rust, без Python-FFI)
senko(math): pi, e, sqrt, sin, cos, tan, pow, log, log10, abs, floor, ceil, round, min, maxkaltsit(file): read-file, write-file, append-file, exists?, is-dir?, list-dir, mkdir, delete, sizew(test): форма(test "имя" body...), assert-eq/true/false, JSONL-вывод по §5.3
Новые типы
Map— ассоциативные массивы: map-get, map-set, map-keys, map-values, map-has?- Дженерик-структуры:
(defstruct (Node a) (value a) (next (Option (Node a))))
JSON-ошибки (§6 спеки V1.0)
- stderr всегда строгий JSON с полями severity, phase, code, message, location, hint, context
- Флаг
--prettyдля человекочитаемого рендера - 32 кода ошибок, включая новые:
integer-overflow,invalid-exit-code,
stack-depth-exceeded,nesting-too-deep,io-error,import-collision,import-cycle
CLI
lupus run <file>(и по умолчанию)lupus test <path>— прогон тестов с JSONL-выводомlupus check <file>— линтер (unused-variable, core-shadowing, missing-return-type и др.)lupus ast <file>— JSON-сериализация AST (§7 спеки)lupus eval "<expr>"— REPL для одного выражения- Флаги:
--pretty,--verbose,--no-lint,--json,--lenient-parens,--version
Тест-система LiF фаза 2
- Fuzz: 10 000 программ локально, 20 000 в CI (env
LUPUS_FUZZ_N) - Oracle-дифференциал против v0.4.0: 104 файла, 92 PASS / 0 FAIL / 12 SKIP
- Coverage map: 111 символов языка с positive+negative ссылками
- Структурированные генераторы: random, edge_cases, type_mix, modules, strings
Безопасность рантайма
- Лимит глубины рекурсии: 10 000 (
stack-depth-exceededвместо SIGSEGV) - Лимит вложенности скобок: 1 000 (
nesting-too-deepвместо паники парсера) - Проверенная арифметика:
checked_div/checked_add/checked_mul— ни одной паники на i64::MIN - Eval в отдельном потоке со стеком 1 GiB (обоснование: debug-сборка переполняет
стандартный стек раньше логического лимита)
Breaking changes от V0.4
- FFI через Python заменён нативными модулями. Директива
(#lupus ffi python "...")
теперь даёт ошибку линтаinvalid-directiveс hint о замене. - Negative-тесты:
.error-файлы теперь содержат код ошибки (одна строка), а не
русскую подстроку. Харнесlifматчит полеcodeиз JSON stderr. run_experiment.py: детект ошибок только поreturncode != 0, без подстрок stdout.(exit n): валидация 0..=255, иначе runtime-ошибкаinvalid-exit-code.- Арифметика i64: переполнения дают
integer-overflowвместо паники.
Известные ограничения
- HM-тайпчекер не реализован (отложен в V1.0). Аннотации типов в
define-public
проверяются только синтаксически (наличие->и типов параметров). - Tensor (
exusiai) отложен в V2.0. - macOS-сборка: кросс-компиляция требует Apple SDK (osxcross), бинарники не поставляются.
- Oracle-дифференциал: для exit≠0 сравнивает stdout по префиксу (V0.4.0 печатал
диагностику в stdout, V0.5 — JSON в stderr). Расхождение в хвосте текста ошибки
дифференциалом не ловится.
Метрики
| Метрика | V0.4.0 | V0.5.0 | Δ |
|---|---|---|---|
| Тестов cargo | 115 | 198 | +72% |
| Golden-файлов | 17 | 34 | +100% |
| Negative-файлов | 71 | 108 | +52% |
| Fuzz-программ | 2 000 | 10 000 (20 000 в CI) | ×5 (×10) |
| Oracle-файлов | 34 | 104 | +206% |
| Кодов ошибок | ~25 | 32 | +7 |
| Покрытие спеки V1.0 | ~35% | ~65–70% | +30 п.п. |
Установка
# Из релизного архива
wget https://github.com/KUARU-dotcom/Lupus/releases/download/v0.5.0/lupus-v0.5.0-linux-x86_64.tar.gz
tar xzf lupus-v0.5.0-linux-x86_64.tar.gz
./lupus --version
# Из исходников
git clone https://github.com/KUARU-dotcom/Lupus.git
cd Lupus
cargo build --release
./target/release/lupus --versionРазработка
- Архитектура и спецификация: Qwen3.8 Max / Qwen3.7 Max
- Реализация: DeepSeek V4.1 Flash (через OpenCode)
- Аудит: NikoGPT (github.com/nikogpt-bot; мультимодельная агентская платформа,
аудит выполнен на DeepSeek V4.1 Flash 1017) — независимый аудит rc1/rc2,
выявление блокеров, проверка borrow-паник в RefCell, кэша модулей, oracle-логики - Стоимость релиза: ~$0.20 (суммарно все агентские сессии)
Документация
Lupus V0.4.0
Lupus V0.4.0
Расширение языка поверх V0.3: числа с плавающей точкой, кортежи, пользовательские
структуры, цикл loop/exit, а также выпускные ворота — тест-система LiF.
- Бинарники в этом релизе собраны из тега
v0.4.0(не из рабочей копии). - Тест-система LiF: 17 golden / 70 negative / 64 символа в карте покрытия.
- Бенчмарк
merged-lupus-2bv2: 81/100, без регрессии к V0.3
(модель ещё не дообучена на синтаксисе V0.4).
Область изменений (скоуп)
| Область | Статус |
|---|---|
| Float: литералы, арифметика, деление IEEE, конверсии, равенство | добавлено |
Tuple: (tuple ...), match-паттерн, равенство, печать |
добавлено |
defstruct: конструктор, аксессоры, match-паттерн |
добавлено |
loop / exit |
добавлено |
| Тест-система LiF (golden/negative/map покрытия) | добавлено |
Числа с плавающей точкой (Float)
Литералы 3.14, 2.5e-3, 0.5 (литералы Number::Float); арифметика
int+int=int, float+float=float, смешивание int+float — runtime-ошибка.
Деление: int/0 — ошибка; float/0.0 → inf, float/(- 0.0) → -inf (IEEE, без
ошибки). % с float — ошибка. Конверсии int->float, float->int (усечение к
нулю), str->float, float->str. Равенство: (= 1 1.0) → false.
Унарный минус работает и для float: (- x) отрицает число с плавающей точкой,
(- 0.0 x) — разность двух float (в т.ч. получение -0.0 через (- 0.0)).
Кортежи (Tuple)
(tuple 1 "a" true) — арность 0+ любая. Доступ только через match-паттерн
(tuple a b c); несовпадение арности — runtime-ошибка. Равенство поэлементное;
печать (tuple 1 "a").
Структуры (defstruct)
(defstruct point (x int) (y int)) — аннотации типов парсятся, но не проверяются.
Автогенерация конструктора (point 10 20) и аксессоров (point-x p). Аксессор на
чужую структуру — ошибка. Дубликат имени поля — ошибка duplicate-struct-field.
match-паттерн ((point x y) ...) связывает поля позиционно.
Цикл loop/exit
(loop тело...) — бесконечный цикл; (exit n) — немедленное завершение процесса
с кодом n.
Тест-система LiF (выпускные ворота)
tests/golden/ (точный stdout, exit 0), tests/negative/ (подстрока ошибки,
exit ≠ 0) и tests/coverage_map.toml (карта покрытия: у каждого символа ≥1
positive и ≥1 negative). Харнес tests/lif.rs прогоняет всё при cargo test и
проваливает сборку при падении любого файла.
Устойчивость лексера: комментарий с одиночной ;
Одиночная ; (не обязательно ;;) теперь начинает комментарий до конца строки.
Раньше одинокий ; вне строки не потреблялся лексером и приводил к зависанию
(бесконечный цикл токенизации). Символов с ; в языке нет, поэтому семантика
валидных программ не изменилась. Добавлен регрессионный тест и guard-таймаут
5 секунд в харнесе LiF (никакой .lupus не может повесить cargo test).
Обсуждение: #21
Lupus V0.3.1
Lupus V0.3.1
Релиз-фикс поверх V0.3.0: исправления гигиены репозитория и метаданных сборки.
Семантика интерпретатора и тесты не менялись.
Исправления
| Область | Что сделано |
|---|---|
| Версия | Cargo.toml/Cargo.lock приведены к 0.3.1 (в V0.3.0 было 0.2.0 при теге v0.3.0) |
| CLI | добавлены флаги --version / -V → Lupus 0.3.1 (через CARGO_PKG_VERSION) |
| Гигиена | удалён мусор (subprocess, RELEASE_NOTES.md), results-файлы консолидированы в results/, спека перенесена в docs/, дедупликация legacy/ + legacy/README.md, добавлен .editorconfig, сняты exec-биты с данных |
| Сборка | релизный профиль: opt-level=3, lto, codegen-units=1, strip, panic="abort"; rust-toolchain.toml; build_release.sh приведён к реальному процессу |
| Размер бинарника | Linux x86_64: ~428 КБ (stripped) — при opt-level=3; сравнение скорости vs opt-level=z (fib(30)): ~2.9 c против ~5.2 c |
Бинарники собраны строго из тега v0.3.1.
Артефакты
lupus-v0.3.1-linux-x86_64.tar.gz— Linux x86_64 (glibc):lupus+LICENSE+README.mdlupus-v0.3.1-windows-x86_64.zip— Windows x86_64:lupus.exe+LICENSE+README.mdSHA256SUMS-v0.3.1— контрольные суммы
Сборка и проверки:
cargo test— 74 теста (72 integration + 2 doc), 0 failedcargo clippy --all-targets— 0 warningscargo fmt --check— чисто./lupus --version→Lupus 0.3.1
Lupus V0.3.0
Заменён релизом v0.3.1 (корректные метаданные версии и оптимизация сборки). Сохранён для истории.
Lupus V0.2
🐺 Lupus V0.2 — The Rust Rewrite
Lupus V0.2 — это первый стабильный релиз интерпретатора, полностью переписанный на Rust. Мы отказались от Python-прототипа в пользу производительности, строгой типизации и модульной архитектуры.
Этот релиз знаменует переход от "эксперимента в одном файле" к полноценному языковому ядру.
🚀 Что нового
⚡ Полная переписка на Rust
Интерпретатор теперь работает на Rust. Это дало нам:
- Мгновенный запуск: Никаких накладных расходов на старт Python VM.
- Безопасность памяти: Строгая типизация на этапе компиляции интерпретатора.
- Модульность: Код разделен на логические компоненты (
lexer,parser,ast,interpreter,environment), что упрощает поддержку и развитие.
🧠 Результаты бенчмарка (LLM Coding)
Мы протестировали дообученную модель Qwen 2.5 (merged-lupus-2bV2) на наборе из 100 алгоритмических задач.
- Общий Pass Rate: 81% (81/100 задач решены верно).
- Арифметика и Логика: 100% (идеальное понимание базовых операций).
- Циклы и Списки: ~85-90% (уверенная работа с
while,list,nth). - Рекурсия: ~80% (факториалы, Фибоначчи, GCD работают стабильно).
Сравнение: Базовая модель без дообучения (Qwen 3.5 2B) показывала ~45% на тех же задачах. Дообучение на датасете Lupus дало прирост +36%.
🛠 Технические детали реализации
- Tree-Walk Interpreter: Классическая архитектура обхода AST.
- Lexical Scoping: Корректная работа замыканий (
lambda) и областей видимости. - Error Handling: Понятные сообщения об ошибках с указанием строки и колонки (на русском языке).
- Built-ins: Реализованы все базовые функции спецификации V1.0 (
print,int->str,string-append,list,nth,length, арифметика).
📦 Установка и запуск
Готовые бинарники
Скачайте архив для вашей ОС в разделе Assets ниже:
lupus-v0.2.0-linux-x86_64.tar.gzlupus-v0.2.0-windows-x86_64.zip
# Linux
tar -xzf lupus-v0.2.0-linux-x86_64.tar.gz
./lupus hello.lupus
# Windows
Expand-Archive lupus-v0.2.0-windows-x86_64.zip
.\lupus.exe hello.lupusСборка из исходников
Требуется установленный Rust toolchain.
git clone https://github.com/KUARU-dotcom/Lupus.git
cd Lupus
cargo build --release
./target/release/lupus examples/hello.lupus📝 Пример кода (Lupus)
;; Факториал с рекурсией
(define (factorial n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
(print (int->str (factorial 5))) ;; Вывод: 120
;; Работа со списками и циклами
(define-mutable sum 0)
(define-mutable i 1)
(while (<= i 10)
(set! sum (+ sum i))
(set! i (+ i 1)))
(print (int->str sum)) ;; Вывод: 55🔜 Что дальше? (Roadmap)
В следующих версиях (V0.3+):
- Расширение стандартной библиотеки (
map,filter,fold). - Поддержка модулей и импортов.
- Оптимизация хвостовой рекурсии.
- FFI (вызов функций C/Rust).
Полная спецификация языка: Lupus V1.0 Specification
Lupus v0.1R Alpha
🐺 Lupus v0.1R Alpha
Исследовательский релиз — первый честный бенчмарк Lupus против Python на 5 LLM-моделях разного размера и точности квантования.
TL;DR
- Lupus — Lisp-подобный язык, спроектированный под маленькие LLM (1.5–14B)
- Гипотеза: «Lupus даёт ≥20% меньше ошибок, чем Python» ❌ не подтвердилась в zero-shot
- Но обнаружен сильный эффект масштабируемости: Lupus растёт круче, чем Python
- Фикс интерпретатора дал +10 п.п. на 2B бесплатно (35% → 45%)
- 1-битный квант 27B-модели набирает 73% на Lupus — уровень честной 9B
📊 Результаты бенчмарка (100 задач)
| Модель | Lupus | Python | Разрыв |
|---|---|---|---|
| Qwen3.5-2B | 45% | 75% | −30 |
| Qwen3.5-4B | 55% | 93% | −38 |
| Qwen3.8-4B-distill | 53% | 96% | −43 |
| Qwen3.5-9B | 74% | 96% | −22 |
| Bonsai-27B (Q1_0, 1-bit) | 73% | 99% | −26 |
Ключевое наблюдение: кривая Lupus идёт 45→55→74 (почти линейно), а Python насытился на 93-99%. Разрыв сужается с ростом модели — это главный сигнал в пользу гипотезы обучаемости.
Bonsai-27B: 1-битная квантованная 27B-модель (4.7 ГБ) показывает 73% на Lupus — паритет с Qwen3.5-9B (74%), при этом Python у неё почти идеален (99%). Преимущество в 3× параметров съедено экстремальной квантовацией: S-выражения оказались чувствительнее к шуму кванта, чем знакомый Python. Провалы Bonsai — те же классы ошибок (галлюцинации let/expt, иммутабельность, небаланс скобок), что подтверждает таксономию на шестой модели.
🔧 Что починили с v0.1e
- Полиморфный
print— теперь принимаетint,bool,strбез явногоint->str. Убрало ~15 ложных падений на арифметике. ifбезelse— снято жёсткое требование 3 аргументов. Модели перестали падать на(if cond (print x)).- Литералы
true/false— добавлены в лексер, больше не нужно определять их черезdefine. - Скрипт бенчмарка —
run_experiment.pyс поддержкой--resume,--ids,--cat,--report. - Шпаргалка LLM —
lupus_cheatsheet.txtна ~800 токенов, единая для всех прогонов.
🧪 Методология
- Интерпретатор: tree-walk на Python (~900 строк)
- Бенчмарк: 100 задач × 2 языка = 200 генераций на модель
- Промптинг: только системная шпаргалка, без few-shot
- Верификация: детерминированная сверка stdout с эталоном
- Температура: 0.1,
max_tokens: 700 - Thinking: отключён во всех прогонах (иначе Qwen3.5 сжигает все токены на reasoning)
📋 Таксономия провалов Lupus
| Класс | Пример | Причина |
|---|---|---|
| Галлюцинации stdlib | expt, append, let, string-reverse |
Модель тянет из Scheme/Common Lisp |
| Иммутабельность | «Переменная sum не изменяемо» | Забывает define-mutable перед set! |
| Небаланс скобок | «Неожиданный токен: RPAREN» | Классика S-выражений у малых моделей |
| Алгоритмические | обратный порядок, off-by-one | Ошибки логики, не синтаксиса |
🎯 Выводы и следующие шаги
- Zero-shot сравнение некорректно — Python в преобучении на терабайтах кода, Lupus — на нуле. Разрыв ~30 п.п. это эффект данных, а не языка.
- Lupus масштабируется — на 9B в «чистых» категориях (arithmetic, logic, strings) уже паритет с Python.
- Квантование — отдельная ось качества — 1-bit 27B ≈ 4-bit 9B на Lupus; для редкого синтаксиса точность весит больше, чем сырой размер.
- Этап 2 (в работе): генерация датасета Lupus учителем (DeepSeek V4 Flash) → LoRA-дообучение 2B/4B → повторный бенчмарк. Честный тест гипотезы: «что легче выучить при равном объёме данных».
- Этап 3 (план): переписать интерпретатор на Rust для production-скорости.
api_client.py Не проверялся!
🐺 Lupus v0.1R Alpha
Research Release — the first honest benchmark of Lupus against Python on 5 LLM models of varying sizes and quantization precision.
TL;DR
- Lupus is a Lisp-like language designed for small LLMs (1.5–14B)
- Hypothesis: "Lupus yields ≥20% fewer errors than Python" ❌ did not hold in zero-shot
- However, a strong scalability effect was discovered: Lupus scales steeper than Python
- Interpreter fix gave +10 p.p. on 2B for free (35% → 45%)
- 1-bit quantized 27B model scores 73% on Lupus — on par with a solid 9B model
📊 Benchmark Results (100 tasks)
| Model | Lupus | Python | Gap |
|---|---|---|---|
| Qwen3.5-2B | 45% | 75% | −30 |
| Qwen3.5-4B | 55% | 93% | −38 |
| Qwen3.8-4B-distill | 53% | 96% | −43 |
| Qwen3.5-9B | 74% | 96% | −22 |
| Bonsai-27B (Q1_0, 1-bit) | 73% | 99% | −26 |
Key observation: The Lupus curve goes 45→55→74 (almost linear), while Python saturated at 93–99%. The gap narrows as model size increases — this is the main signal in favor of the learnability hypothesis.
Bonsai-27B: A 1-bit quantized 27B model (4.7 GB) achieves 73% on Lupus — parity with Qwen3.5-9B (74%), while its Python score is near-perfect (99%). The 3× parameter advantage is eaten up by extreme quantization: S-expressions turned out to be more sensitive to quantization noise than familiar Python. Bonsai's failures are the same error classes (hallucinations of let/expt, immutability, paren imbalance), confirming the taxonomy across a sixth model.
🔧 What Was Fixed Since v0.1e
- Polymorphic
print— now acceptsint,bool,strwithout explicitint->str. Eliminated ~15 false failures in arithmetic. ifwithoutelse— removed the strict 3-argument requirement. Models no longer crash on(if cond (print x)).true/falseliterals — added to the lexer; no longer need to define them viadefine.- Benchmark script —
run_experiment.pywith support for--resume,--ids,--cat,--report. - LLM cheat sheet —
lupus_cheatsheet.txtat ~800 tokens, unified across all runs.
🧪 Methodology
- Interpreter: tree-walk in Python (~900 lines)
- Benchmark: 100 tasks × 2 languages = 200 generations per model
- Prompting: system cheat sheet only, no few-shot
- Verification: deterministic stdout comparison against reference
- Temperature: 0.1,
max_tokens: 700 - Thinking: disabled in all runs (otherwise Qwen3.5 burns all tokens on reasoning)
📋 Lupus Failure Taxonomy
| Class | Example | Cause |
|---|---|---|
| Stdlib hallucinations | expt, append, let, string-reverse |
Model draws from Scheme/Common Lisp |
| Immutability | "Variable sum is not mutable" | Forgets define-mutable before set! |
| Paren imbalance | "Unexpected token: RPAREN" | Classic S-expression issue for small models |
| Algorithmic | reverse order, off-by-one | Logic errors, not syntax |
🎯 Conclusions and Next Steps
- Zero-shot comparison is unfair — Python has terabytes of code in pretraining, Lupus has zero. The ~30 p.p. gap is a data effect, not a language effect.
- Lupus scales — on 9B in "clean" categories (arithmetic, logic, strings) it already achieves parity with Python.
- Quantization is a separate quality axis — 1-bit 27B ≈ 4-bit 9B on Lupus; for rare syntax, precision matters more than raw size.
- Stage 2 (in progress): generating a Lupus dataset with a teacher (DeepSeek V4 Flash) → LoRA fine-tuning 2B/4B → re-benchmark. An honest test of the hypothesis: "what is easier to learn given equal data volume".
- Stage 3 (planned): rewrite the interpreter in Rust for production speed.
api_client.py Not tested!