Skip to content

Latest commit

 

History

History
353 lines (287 loc) · 31.4 KB

File metadata and controls

353 lines (287 loc) · 31.4 KB

Два потока в одну модель — DoD

Статус: зафиксировано 2026-09-11 по итогам обсуждения с владельцем; проверено продюсером (см. «Поправки продюсера» ниже). Кода нет.

FDML — не один pipeline, а два конвейера, сходящиеся в один граф:

                 USER intent / value
                        │  forward: LLM-черновик, человек объявляет
                        ▼
FORWARD ───────────► FEATURE ◄──────────── REVERSE
                        │                    ▲  candidate, inferred
                        ├── SOLUTION         │
                        ├── ENGINEERING   PRODUCT DOMAIN (интерпретация)
                        ├── CODE             ▲
                        └── EVIDENCE      ENGINEERING (observed)
                                             ▲
                                           SCAN ◄── SOURCE CODE

DoD: Domain + два потока

  1. Forward flow. USER INTENT → LLM → VALUE + CONSUMER + PRODUCT DOMAIN → FEATURE → SOLUTION → ENGINEERING → CODE → EVIDENCE. Доказано на 3–5 реальных фичах, что domain и consumer реально помогают сформировать Feature.
  2. Reverse flow. SOURCE CODE → SCAN → OBSERVED ENGINEERING STRUCTURE → PRODUCT DOMAIN → LLM → CANDIDATE FEATURE. Доказано на существующем проекте (Doom), что из кода получаются осмысленные candidate features.
  3. Граница reverse. Reverse восстанавливает что система делает (observed / inferred), но не имеет права утверждать зачем, для кого, какую ценность. Нет в источниках — unknown.
  4. Provenance на каждом шаге: declared | observed | inferred | verified | unknown; определяется источником знания, не доменом.
  5. Domain — не отдельная модель проекта и не второй глоссарий: внешний термин → существующая сущность проекта → owns / invariants. Импорт только по требованию.
  6. Язык. После эксперимента фиксируются только необходимые: consumers, domains, value.for, feature.domain, consumer.kind, правила lint.
  7. Доказательство архитектуры. Оба потока сходятся в один граф, не в две модели.

Один и тот же Feature эволюционирует по эпистемическому статусу: observed structure → inferred candidate → declared feature → verified implementation.

Поправки продюсера

  • Критерий «пользователь не пишет Feature руками» противоречит п. 4. declared означает «человек написал или принял». Точная формулировка: LLM пишет черновик (inferred), человек объявляет (declared). Автор фичи — человек, автор текста — кто угодно. Иначе forward-flow производит фичи со статусом inferred, которые никто не объявил, и вся цепочка доказывает inferred-намерение.
  • Forward-flow с LLM — не измерен. enrich --tier llm существует в ядре (локальный Ollama, схемно-ограниченная проза), но записанный опыт с локальными моделями отрицательный: сборка платформы падала на малых моделях, search --llm дал +4 п.п. за 8,5 с на запрос. DoD п.1 опирается на неизмеренный компонент; измерять его надо на reverse (п. 2), где ошибка модели дешевле — она предлагает, а не объявляет.
  • Порядок. Reverse-эксперимент на Doom идёт раньше consumers/domains: он покажет, какие именно domain-связи нужны, а не какие красиво выглядят. Скан Doom уже есть (граф вызовов сверен с clang), цена эксперимента — один прогон enrich.
  • Число для п. 2 надо назначить до прогона, иначе «осмысленные» решит вкус: из N candidate features человек принимает k как declared без переписывания; порог и N записываются до запуска, результат — в research/.

Reverse flow на Doom: первый результат (2026-09-11)

Старый подход — дамп наблюдаемой структуры (18,8k символов) в модель — даёт кандидатов уровня подсистем и не рентабелен: малая локальная модель 70 с и 4/10 продуктовых формулировок, средняя не ответила за 40 минут.

Новый порядок SOURCE → static analysis → index → behavioral units → compact index → LLM работает: юниты извлекаются детерминированно из сверенного с clang графа вызовов (270 точек входа → 98 юнитов, два прогона — один дайджест), top-30 занимает 3,5k токенов, и Haiku по нему даёт 10/10 кандидатов с нулевой утечкой намерения, полной привязкой к индексу и продуктовыми формулировками 9/10; с внешним словарём жанра 10/10 и все названы терминами домена. Восемь из десяти кандидатов в двух независимых прогонах указывают на одни и те же юниты: выбор делает индекс, модель делает только переход observed → product. Подробности и таблица — research/reverse-flow/PROTOCOL.md. Принятие владельцем (k ≥ 5/10) ещё не снято.

Reverse Flow v1: принято (2026-09-11)

Владелец принял эксперимент. Формулировка результата:

Behavioral index — достаточное компактное представление наблюдаемой системы для reverse candidate extraction. Детерминированный индекс выбирает поведенческий субстрат; LLM выполняет только перевод observed → product-domain candidate. Словарь домена улучшает терминологию, не меняя выбранное поведение.

Доказано на одном проекте (C, выраженные точки входа, хорошие имена). Не доказано: другой тип приложения, другой язык, плохие имена, граф без точек входа, огромный граф, способность, размазанная по слабосвязанным участкам. Не чинить заранее.

Граница ответственности:

SOURCE → STATIC ANALYSIS (entities, functions, calls, types, flows)
       → BEHAVIORAL UNITS (entry points, reachability, clustering, deterministic ranking)
       → BEHAVIORAL INDEX (observed facts + product-domain vocabulary)
       → LLM → CANDIDATE FEATURE (inferred)

LLM не имеет права утверждать: why, value, consumer, original intent.

Старый путь (дамп → LLM) — экспериментальная база, не production path. Порог принятия не повышать: гипотеза подтверждена, эксперимент закончен.

Долг, зафиксированный как потребность, не как фикс: юниту нужен types_used — факт статического анализа «функция использует тип», а не совпадение слова в имени.

Эталон: declared против observed на одном проекте (2026-09-11)

Из двух дизайн-документов 1992 и 1994 годов и заметки владельца собран эталонный vision.fdml для внешнего C-проекта: 7 корней с value из метрик самой игры, 41 фича со статусом против кода (26 implemented, 6 changed, 7 dropped, 2 design), реализующие функции проверены по индексу, трассируемость от сканированных фич к эталону сгенерирована детерминированно. fdml validate принимает его как граф ценности.

Что эталон дал сразу:

  • три оси gap числом: 95 из 263 сканированных фич реализуют замысел, 168 — структура без замысла; 7 замыслов без кода (dropped); 2 замысла, которые не код;
  • reverse-кандидаты измеримы: 10 кандидатов достигают 21 из 32 подкреплённых кодом фич эталона; список недостигнутых — это «что искать в коде дальше», список dropped — «чего нет и не будет»;
  • баг ядра: файл с суффиксом _spec считался тестом, 18 функций выпадали из графа; починено.

Эталон живёт в research/reverse-flow/external-c-etalon.fdml и генерируется etalon.py.

Recall reverse flow против эталона (2026-09-11)

Эталон 41 → подкреплены кодом 32. Десять кандидатов достигают 21 из 32 (unit-level), двадцать — 28 из 32, при нулевой утечке намерения и полной привязке. Таксономия одиннадцати промахов первого прогона, решённая по данным: ни одна фича не отсутствовала в детерминированной абстракции; восемь были показаны и не выбраны (лимит на число кандидатов, снят вторым прогоном); две опосредованы хабами (сквозные поведения вроде урона не живут ни в одном юните); одна ушла ниже top-30.

Строгий recall, когда считаются только функции, названные кандидатом, ниже: 14 и 17 из 32. Разрыв — «названо слишком общо»: кандидат указывает на нужный юнит и называет два-три его члена. Для связи кандидат → код хватает первого, для формулировки фичи честнее второе.

Три остаточных ограничения v1 записаны, не чинятся: хабы, хвост ранжирования, целое против частей. Карты домена построены только из того, что появилось в источниках, эталоне и восстановленном; solution-домен — из механизмов FAQ и 168 сканированных фич без замысла по семействам модулей. Всё в research/reverse-flow/.

Состояние Reverse Flow v1 (закрыто 2026-09-11)

Observed abstraction     COMPLETE vs etalon (A1 = 0: все 32 кодовые фичи представлены)
        │
Candidate retrieval      WORKING (10 → 21/32, 20 → 28/32 unit-level; strict 14 → 17)
        ├── B   ranking / budget      — снято бюджетом кандидатов
        ├── A2  long tail             — ниже top-30, чистый retrieval
        ├── C   coarse naming         — 28 против 17: указывает на юнит, называет 2–3 члена
        └── D   cross-cutting hubs    — сквозные поведения через хабы не представлены v1

Никакая улика сейчас не оправдывает изменение сканера, абстракции, построения юнитов, новой онтологии, RAG или разрезания хабов. Следующий объект — не extraction, а стыковка forward и reverse: как восстановленный product domain и эталонный vision.fdml ложатся на то, что FDML уже умеет для forward-flow, и нужны ли consumers/domains из планируемого 1.4.3 по факту, а не по теории.

Стыковка forward/reverse (2026-09-11)

Forward-инструменты принимают эталонный vision.fdml как есть: strict-валидация чистая, 142 связи realizes разрешаются, evidence пуст, ни один из 41 сценариев ещё не верифицирован тестом. Граф сходится без новых конструкций; не хватает тестов и доказательств, не языка.

Проверка полей 1.4.3 по факту, на всех 41 фичах эталона: потребителей в источниках два, игрок и автор уровней; второй владеет пятью фичами и его появление создало восьмой корень и перенесло три фичи. beneficiary из 1.4.1 этого выразить не может: оба user. value.for оправдан. Область домена не изменила ни одной формулировки и ни одного корня; единственную переклассификацию сделал существующий layer: system. domains откладывается. Оба поля сегодня молчат: парсер игнорирует неизвестные ключи, поэтому for без lint ничего не значит.

Knowledge layer: откладывается конструкция, не знание (2026-09-11)

Уточнение к предыдущему разделу: domains как формальная конструкция языка откладывается; доменное знание (термины, механики, правила, инварианты, связи с фичей, решением и кодом, источник) обогащается уже сейчас, и цель этого слоя — поиск. Проверено ленивой версией на эталоне: четыре доменных вопроса к индексу внешнего проекта промахивались 4 из 4; пять механизмов из дизайн-FAQ, записанные штатными нотами навигатора с якорем на функцию и алиасами, дали 5 из 5 первым результатом: продуктовый смысл, механика, код и источник в одной строке. Новых конструкций ноль. Порядок: consumers + for + lint → tests + evidence → обогащённый домен на эталоне → поиск по нему → vision FDML → gap → decisions.

Финальная модель текущего этапа (2026-09-11)

  • Feature — база: единственный объект, через который сходятся документы и код.
  • Notes — knowledge layer: термины, механики, правила, инварианты, решения, с якорем на код и provenance в теле.
  • Evidence — доказательство: тест → verifies → сценарий → фича.
  • Consumers / value.for — кому принадлежит ценность; доказано вторым потребителем.
  • Layer — граница product / system; пока хватает.
  • Domain — обогащается через ноты, в язык не входит до доказанной необходимости.
  • Decision — не вводится. Вычеркнут из очереди по данным: Feature нужен постоянно, Decision ни разу не заставил себя ввести. Решение «X вместо Y» — нота kind rejected/method/invariant с provenance. Возврат только при постоянной потребности машинно связывать решения с фичами, искать их и проверять supersedes. Provenance status из 1.4.2 §4 остаётся отдельным вопросом на момент, когда reverse-кандидат пойдёт в FDML-файл как inferred.

Порядок до среза v1: consumers + for + lint → 41 сценарий → tests → evidence → домен в ноты → бенчмарк поиска по нотам → vision.fdml самого FDML (3–5 фич с for) → gap → посмотреть, что осталось. Срез v1: DOCUMENT INTENT → FEATURE ↔ KNOWLEDGE ↔ OBSERVED CODE → EVIDENCE.

Куда ложится облако домена (2026-09-11)

Почти всё — в существующие элементы. Правила и инварианты домена — это constraints из 1.3 с ссылкой actions на сканированные действия: шесть правил дизайн-FAQ добавлены в эталон, strict-валидация чистая. Механики и solution-цепочки — ноты навигатора с якорем на функцию, они уже отвечают на доменные вопросы 5/5. Термины — описания сущностей скана и алиасы нот. Способности — фичи эталона. Потребители — единственная новая конструкция, 1.4.3. Без дома остаётся только область как группировка, и она пока ничего не меняет, поэтому и отложена. Настоящая дыра — переносимость нот: они живут в индексе, не в файле; это задача инструмента, не языка.

Инвариант: Stack, Product, Engine Product, Domain (2026-09-11)

В одном исходнике три объекта рассмотрения, и переходы между ними не автоматические:

  1. Stack — техническая среда: язык, компилятор, движок, инструменты. Контекст, в котором продукт существует; сам по себе не набор пользовательских фич.
  2. Product — то, у чего есть потребитель и ценность (игрок, автор уровней).
  3. Engine Product — самостоятельный продукт со своими capabilities (рендер, звук, коллизии, секторы, триггеры, загрузка данных), который реализует фичи продукта. Одна продуктовая фича реализуется десятками engine-capabilities.
  4. Domain knowledge описывает мир. Оно объясняет, ограничивает и обогащает фичу, но само по себе не создаёт ни фичу, ни требование к движку или стеку.
  5. Требование к Engine или Stack возникает только из объявленной Product Feature через явную реализационную связь.
DOMAIN ── enriches ──► PRODUCT ── requires realization ──► SOLUTION ──► ENGINE PRODUCT ──► STACK
DOMAIN ──────X───────────────────────────────────────────► ENGINE   (никогда напрямую)

Reverse идёт иначе и тоже без автоматики: CODE → observed engine capability → candidate feature → возможно связано с продуктом и доменом.

Следствие для gap: gap считается относительно объявленного Product Intent, а не относительно всего, что есть в domain knowledge. «В домене есть возможность X, в коде её нет» — не gap. Gap: «продукт объявил X, код не реализует», «код реализует, замысел не объявлен», «потребитель объявлен, фичи для него нет».

Следствие для эталона: он смешивает два продукта. Фича «рендер» и 168 сканированных фич без замысла — это capabilities engine-продукта, а не игры; у engine-продукта может быть свой vision со своим потребителем (разработчик игры на этом движке). Не переписывать сейчас; учесть при gap и при vision самого FDML, где такой же вопрос: FDML-язык и FDML-инструмент — два продукта с разными потребителями.

Граница контекста продукта, измерена (2026-09-11)

Потребитель не обязан быть в сканируемом репозитории: мы сканируем движок, а потребители и ценность принадлежат игре и живут во внешнем контексте. Четыре режима на одном движке и одном эталоне: без контекста модель достигает 27 из 32 фич эталона движковыми словами; с идентичностью продукта то же покрытие, но появляется атрибуция потребителя и второй потребитель не восстанавливается; с тем же кодом под другим продуктом, SDK, 17 из 20 юнитов те же, 2 из 20 названий те же, потребители меняются полностью и рендер становится фичей. Выбор делает индекс, интерпретацию — контекст продукта: фичу продукта нельзя восстановить из кода движка без контекста. Негативный контроль на внутренних юнитах: выдуманных фич ноль, ошибка только в гранулярности. Описательный слой поверх юнитов проверен и отклонён: recall, названия и выбор не изменились. Артефакты 04 и 05 в research/reverse-flow/.

Данные продукта как слой (2026-09-11)

Проверено на shipped-данных игры: детерминированный инспектор превращает карту в описание в словаре самой игры (старты, монстры, оружие, ключи, двери, триггеры, выходы, секреты, опасные полы). Слепой модели эти данные вредят: кандидаты превращаются в инвентарь уровня, покрытие эталона падает с 27 до 18 из 32. С контекстом продукта те же данные становятся уликами: покрытие 28 из 32, продуктовых формулировок 17 из 20, 12 кандидатов цитируют факт из уровня, выдуманных ноль. Описание данных не мост от структуры к фиче, а evidence для фичи, которую контекст продукта уже сделал именуемой. Знание обогащает, не создаёт.

Четыре роли, и как их разводить (вердикт визионера, 2026-09-14)

Verdict: aligns для инварианта; conflicts для любой новой конструкции под него.

Роли — это разные источники, а не разные слои документа:

роль что это где живёт уже сегодня
Domain знание о мире; объясняет, не порождает ноты, constraints 1.3
Product что обещает продукт: consumers, value, intent vision.fdml: его system + consumers (1.4.3) + фичи с value
Engine что предоставляет реализация: observed capabilities сгенерированный спек: system со system_type/technology из discovery, 263 фичи
Data evidence о реальном продукте tests + evidence файлы; WAD-описание — ещё один раннер

Разводить — не полем и не layer. layer отвечает «на каком уровне», а не «чей это продукт»; и layer: system уже занят рендером. Разводит пара документов: vision.fdml = продукт, .fdml/spec/* = наблюдаемый проект, realizes = мост. Второй продукт на том же движке (SDK) — это второй vision-файл с другими consumers, не второй скан.

Product Context declaration уже существует: vision.fdml есть декларация продукта (system.id + consumers), а сгенерированный спек есть декларация наблюдаемого проекта (system.id + system_type). Не хватает одного слова — роли наблюдаемого проекта относительно продукта (engine | game | tool | library). Ленивая версия: не поле языка, а description у system в vision («realized by the engine repository X»), пока роль не понадобится машине.

Reverse-run контракт — тег прогона, не конструкция: каждый candidates.json несёт {analyzed: <spec system.id>, product: <vision system.id | none>, consumers: [...]}; без vision — product: none, и кандидаты остаются engine capabilities. Это исследовательское правило в research/reverse-flow/PROTOCOL.md; в язык — когда кандидат впервые пойдёт в .fdml со статусом inferred.

Cost of yes: ноль новых понятий; одно правило протокола; один абзац в 1.4.1 §3, называющий два потока по имени. Не делать: scope, role у Feature, новый документ product context.

Шаг 2 как артефакт: два набора фич на один репозиторий (2026-09-14)

Из одного сканированного спека сгенерированы две папки. engine/vision.fdml — продукт движка: потребители разработчик игры и автор уровней, 30 фич по одной на behavioral unit со статусом inferred в описании, 447 связей realizes от сканированных фич, 25 флоу из скана. product/vision.fdml — игра: потребители игрок и автор уровней, 41 объявленная фича и 8 корней с value, 142 связи от скана, 84 связи realized_by к фичам движка, 6 констрейнтов из дизайн-FAQ. Обе папки проходят strict-валидацию, все связи разрешаются. Ни один сценарий пока не верифицирован тестом. Обнаруженная дыра инструмента: набор документов собирается из одной папки, два продукта на одном спеке подцеплены симлинками; нужен набор проекта с несколькими vision-файлами.

Рабочая история второго потока: инструмент, не скрипты (2026-09-14)

fdml index . && fdml all .              структура и сканированный спек
fdml propose --product product/vision.fdml --consumer player --consumer level_author
                                        .fdml/spec/candidates.fdml: 30 фич status: inferred,
                                        тег контекста, 505 realizes от сканированных действий
fdml note --import .fdml/notes.json     домен из внешних источников (round-trip проверен)
fdml validate product/vision.fdml       набор проекта: несколько vision на один спек
fdml gap product/vision.fdml            71/80 покрыто, 9 roadmap (= 7 dropped + 2 design
                                        эталона), 103/293 orphan — capabilities движка

Кандидаты из команды воспроизводят исследование дословно: 98 юнитов, top-30 достигают 28 из 32 кодовых фич эталона, те же четыре мимо. Провenance status в парсере; realized_by понимается как обратное realizes. Ноты имеют файловую форму, но .fdml/ игнорируется git — экспортированные ноты в репозиторий не попадают без решения владельца и аудита содержимого.

Не сделано из очереди: consumers + value.for с lint (1.4.3), fdml accept, тесты и evidence на сценарии, карточка во viewer. Гипотезы, проверенные и снятые по дороге: описательный слой, данные продукта как слой, домен как детектор.