INDB: когда все лгут, помнит, что вы видели. agents.. agents. Data Engineering.. agents. Data Engineering. database.. agents. Data Engineering. database. database development.. agents. Data Engineering. database. database development. llm.. agents. Data Engineering. database. database development. llm. nosql.. agents. Data Engineering. database. database development. llm. nosql. python.

В любой записи в базу зашито допущение: у факта одно значение. Два несовпадающих наблюдения об одном объекте — конфликт, который положено разрешить до коммита, и разрешается он UPDATE. Пока данные генерирует ваш же код, допущение верное.

Ломается оно на наблюдениях. Сенсоры расходятся в показаниях, и оба показания настоящие. Агент пишет о состоянии файла, который человек уже поправил руками. Два источника сообщают разное, и разрешить противоречие в момент записи нечем — контекст, в котором одно из них весит больше, появляется только в момент вопроса.

INDB стоит на этом: смысл производится при чтении, а не фиксируется при записи. Вместо CRUD три фазы — вдох (Inhale, принять сырое наблюдение), выдох (Exhale, сжать повторы и отфильтровать шум репутацией), аксиома (Axiom, подписать то, что выжило).

Событие вместо строки

Миграций нет, есть универсальный Event. Заполнить в нём обязательно два поля: токены-сигналы raw_data_anchor и место location. id и timestamp система ставит сама, остальное опционально — ttl, temporal_metadata для временных фильтров, source_id со ссылкой на реестр источников, blind_payload, binary_payload, счётчик слияний fusion_count с флагом is_fused и signature, если событие подписано клиентом.

curl -X POST https://api.indb.tech/api/v2/events 
  -H "Content-Type: application/json" 
  -d '{"raw_data_anchor":["server","heartbeat","ok"],"location":"infra/edge/eu-west","ttl":86400}'

Это «что, где, когда, от кого, насколько часто». Нужно сорок колонок — вы проектируете архив, а не память, и это другой инструмент.

Восемь типов вместо шестидесяти

Система типов классической СУБД в основном описывает раскладку на диске и в памяти, а не смысл: int2 против int4 — калибр, varchar(n) против text — исторический артефакт. Планировщику нужно, интерпретации нет, а платится миграциями.

Восемь типов INDB отвечают не на «как это лежит», а на «что с этим делать движку»:

Тип INDB

Зачем он в системе типов

Покрывает типы PG

number

По нему модули считают арифметику и дистанцию; диапазон в min/max, а не в имени типа

smallint, integer, real, double precision, numeric, money, serial

blind

Непрозрачность проверяема протоколом только когда она свойство типа, а не соглашение прикладного слоя

bytea + pgcrypto с самописной обвязкой

bigint

Наносекунды и криптозначения не влезают в float64, а округление здесь портит доказательство

bigint, numeric для целых, bit varying

string

Из него Echo набирает токены и гармоники; ограничение длины — в схеме поля, не в типе

char, varchar, text, xml, tsvector, tsquery

null

Prism различает «не наблюдали» и «наблюдали пусто», иначе perception_gap считается по выдумке

NULL с трёхзначной логикой

struct

Внешние payload приходят вложенными как есть; валидация рекурсивная, без миграции

json, jsonb, hstore, композитные, домены

binary

Форма нужна для квот, TTL и транспорта; содержимое интерпретировать незачем

bytea, large objects

location

Половина веса в Echo: пространство участвует в выводе, а не доживает в WHERE

point, line, box, polygon, circle, PostGIS geometry/geography

Тип выводится сам: словарь с lat/lonlocation, сырые байты — binary, вложенный словарь — struct. DDL нет.

Платите контролем над раскладкой байтов, индексами под конкретный числовой тип и точной десятичной арифметикой. Банковский леджер на этом не строят.

Модули, которые читают смысл

Раз смысл не записан, его кто-то должен произвести на чтении. Этим занимаются модули интерпретации, и все они read-only: в хранилище не пишет никто из них, писать умеют только Inhale и Fusion.

Prism — контекстный синтез вокруг seed-события. Собирает облако смысла из токенов и локации, считает significance_score (редкие токены весят больше, плюс коэффициент кластеризации по локации и fusion_count) и вешает context_labelObjective Data, Pattern, Anomaly или Background. Возвращает не только вывод, но и уверенность в нём с конкурирующими прочтениями.

Echo — резонанс. Строит гармонический отпечаток якоря из множества токенов, эмоциональной классификации и метаданных локации, затем оценивает каждое событие в памяти по формуле 0.20 × токены + 0.30 × эмоции + 0.50 × мета и отдаёт то, что прошло порог 0.3.

Instinct — тот же вопрос с ручкой адреналина 0.0–1.0. На нуле аналитический режим с глубоким разбором токенов и уверенностью около 10%, на 0.5 alert (~46%), на единице чистый рефлекс по метаданным (~82%). Поверх работают триггеры: совпадение локации даёт +0.7 к уверенности, подпись владельца +0.5, критические токены +0.3.

Deduction — вывод цепочками. По набору seed-событий и запросу в заданном радиусе достраивает связи и выдаёт заключение вместе с самой цепочкой, а не только итог.

Subwave — горизонтальный бродкаст. Echo пускает волну по плоскости токенов, локации и времени, Subwave настраивает достижимые узлы на одну частоту — подпись якоря плюс опциональный модификатор, — и те, что залочились (lock = W_res × resonance + W_tok × token_alignment + W_fac × factor_alignment), образуют связный кадр в resonance_edges.bin. Пересчитывать всю память не нужно, отвечают только узлы с реальной массой.

Slice и What-if — сдвиг облака модификатором: смысл движется, якоря стоят, исходные события не меняются. What-if это базовый запрос плюс slice, и в режиме core он работает без LLM — арифметика по графу, модель нужна максимум для пересказа.

Lens — Triple-Half: два контекста смешиваются в заданной пропорции, 90/10 в пользу свежего для алертинга, 10/90 для долгих закономерностей. Один корпус, разные ответы.

Место как индекс

location принимает логический путь (books/Dostoevsky/The_Idiot) или OSM-объект с координатами и валидируемым osm_id для node/way/relation. Один тип вместо геометрического зоопарка и PostGIS сверху.

Те самые 50% веса в Echo — это оно: на наших данных место оказалось сильнейшим предиктором связи между наблюдениями, сильнее и токенов, и эмоциональной окраски. Расстояние считается по гаверсинусу; несколько osm:-токенов в одном событии Fusion штрафует, иначе всё склеивается по географическому совпадению.

API, который спрашивает, а не выбирает

Эндпоинты названы глаголами памяти, потому что отвечают не на те вопросы, что SELECT. POST /events — это Inhale, поток append-only: ни UPDATE, ни DELETE по событию не существует в принципе, изменить прошлое нечем. POST /interpret не забирает данные, а запрашивает перспективу: контекст и цель решают, какие воспоминания всплывут первыми. GET /search считает гармоническую близость вместо LIKE '%текст%'.

Отдельно про парадокс, потому что слово в контексте БД звучит туманно. Парадокс в INDB — не баг и не исключение валидации, а явно зафиксированное состояние двух видов: либо есть факт наблюдения объекта, но нет данных о содержимом, либо два подписанных источника выдают взаимоисключающие сигналы и оба имеют право. POST /paradox заводит такой контекст с пустым raw_data_anchor, пока никто не наблюдал, в отдельном хранилище, а не флагом на событии; на чтении та же ситуация видна как is_paradoxical от Prism.

Чем то же самое приходится делать в обычном стеке:

Глагол INDB

Собирается сейчас из

POST /events

INSERT плюс апсерт-логика дедупликации и запрет на UPDATE дисциплиной команды

POST /interpret

SELECT + прикладной ранжировщик + реранкинг результатов RAG

POST /lens/query

два запроса с разными временными окнами и смешивание весов в коде

GET /search

LIKE/tsvector либо внешний вектор-стор с cosine

POST /subwave/broadcast

рекурсивный CTE или отдельная графовая БД рядом

POST /slice

копия данных, UPDATE в транзакции, ROLLBACK

POST /what-if

промпт к LLM поверх выборки, без воспроизводимости

POST /paradox

строка с NULL и флагом «ещё не наблюдали» в прикладном коде

POST /grain/verify

подпись, N-of-M кворум и статистика — три библиотеки и клей между ними

Транспорт — HTTP, GraphQL, WebSocket, gRPC, UDP, MCP. Внешних баз в ядре нет: ни Redis, ни Postgres, ни Mongo.

TUI: всё то же самое без curl

Наблюдать это из curl неудобно, поэтому в поставке есть полноэкранная консоль на Textual — подключается к живому API, по умолчанию к продовому, INDB_API_URL переключает на локальный узел или балансировщик:

cd db && ./start_tui.sh
python3 -m cli.indb_cli tui --api http://localhost:8888
docker compose --profile tools run --rm tui
┌──────────────────────────────────────────────────────────────────────────┐
│  INDB                          https://api.indb.tech · clock             │
│  [████████░░░░] Loading Events…                                          │
├──────────────────────────────────────────────────────────────────────────┤
│ Control │ Events │ Modules │ Cluster │ Query │ Analytics │ Scripts       │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│                     [ active tab content ]                               │
│                                                                          │
├──────────────────────────────────────────────────────────────────────────┤
│  q Quit   r Refresh   e Events   m Modules   p Query   a Analytics  …    │
└──────────────────────────────────────────────────────────────────────────┘

Семь табов, переключение цифрами и буквами (e события, p запросы, a аналитика, s скрипты, r обновить всё). Control держит total events, процент fusion-сжатия, статус сервера и CPU/RAM, плюс кнопки Run Tests, Run Audit и Restart — локально; в контейнере они скрыты. Events — живой поток с клиентским фильтром и серверным /api/v2/search, где помечает слитые события. Cluster опрашивает /health и /raft/status по каждому узлу и показывает, кто лидер и на каком term.

Главное там — Query Lab: все когнитивные вызовы из предыдущего раздела с полями вместо JSON-тела. Interpret ходит как Neutral | books/Bible/KJV | peace, Echo Resonate принимает UUID, скопированный из таба Events, рядом Prism Synthesize и Instinct с адреналином 0.0–1.0, Lens, Deduction, What-If, Context Slice, Paradox Create/Read и Recovery Identity по key_id. Отдельный таб Scripts гоняет против живого API integrity check, explore_db, audit_protocols, analyze_books и проверку интеграции с Hermes, стримя stdout в лог.

Тот же набор есть в браузере как WUI, если терминал не ваш способ смотреть на систему.

Ответ, который признаёт, что не уверен

Prism возвращает основное прочтение и рядом alternative_readings — конкурирующие версии сохраняются. perception_gap от 0 до 1 мерит неоднозначность, от 0.25 поднимается is_paradoxical. Противоречие — сигнал, а не ошибка валидации.

has_unread_essence включается при наличии blind_payload: вывод построен по токенам, но у события есть закрытая часть.

У Grain четыре вердикта вместо true/false: verified, likely_same_origin, insufficient_signal, rejected. Ради insufficient_signal всё и делалось — двадцать токенов не дают статистического доказательства, и честнее сказать «сигнала недостаточно», чем натянуть уверенность.

Каждый ответ опечатан Ed25519 серверным ключом: проверяет кто угодно, включая недоверяющую сторону. В транзите не подменить, задним числом не переписать.

Подпись с двух сторон

Ответы сервера подписаны всегда — приватный ключ в env, публичный отдаётся открыто. События подписывает клиент локально и по желанию: ключ не уезжает с устройства, его нет ни в теле запроса, ни в логах, ни в recovery API. UDP-телеметрию подписывать дорого и незачем, юридически значимое наблюдение — обязательно.

signed и valid в ответе разделены: «не подписано» и «подпись не проходит» — разные факты.

Идентичность — key_id = SHA-256(public_key). На нём держится восстановление: приватного ключа, seed и общего секрета в протоколе нет.

«Мы не читаем ваши данные» — политика, а политика меняется вместе с владельцем компании. Подпись не меняется.

Blind: аналитика без доступа к содержимому

Шифруете на клиенте, INDB получает непрозрачный блоб, репликует по Raft и возвращает по запросу, ни разу не прочитав: ключа на сервере нет.

Содержимое не попадает в поиск, логи, WUI и TUI, и движок не знает, что два блоба хранят одно и то же — одинаковый текст с разными nonce даёт разные блобы. Заодно отваливается корреляционная атака «эти двое хранят одинаковое», на которой строится половина деанонимизации.

Место, время, открытые токены, источник с репутацией, частота и паттерн обращений при этом видны полностью — Prism, Echo, Instinct, Deduction и Fusion работают по метаданным на всю глубину. Больница ищет корреляции по ["pain","chest","night"] и локации clinic/cardiology, а имя пациента, диагноз и текст заметок лежат в blind_payload и невидимы для её собственной инфраструктуры.

Сверху Black Box Contract, который проверяется протоколом:

Вы можете скрыть, что внутри. Вы не можете скрыть, что вы здесь были.

С blind_payload обязательны непустой location и timestamp в пределах ±5 минут от серверного — иначе можно подсунуть старое перехваченное событие. На любой запрос система отвечает одно: «Что-то здесь было. Это место. Это время.»

И сразу про границу доверия, которая у этой схемы одна:

Client Trust Boundary. Всё, что гарантирует INDB, кончается на вашем устройстве. Сервер блоб не прочитает и ключ не держит, но клиентский код обязан не утащить ключ в логи, крашрепортер или аналитический SDK — за этой чертой мы ничего доказать не можем.

Grain: любая верификация — это сигнал в шуме

Строгий Ed25519 — уровень штрихкода, шума не терпит вообще. Для аксиом правильно, для памяти нет: цитаты бывают частичными, экспорт бьётся, поверхность меняется. Штрихкод, QR, биометрия подписи и водяные знаки вроде SynthID лежат на одной оси устойчивости к шуму, каждый в своей точке — Grain держит всю ось в одном модуле ядра:

Тир

Аналог

Устойчивость

Механизм

exact

штрихкод EAN-13

~0–5%

Ed25519 / key_id

redundant

QR (Reed–Solomon)

~30%

N-of-M кластер подписанных событий

resonant

рукописная подпись

~30–50%

Echo × репутация источника

statistical

SynthID

p-value

отпечаток распределения n-грамм

tier: auto выбирает тир по доступным доказательствам, tolerance крутит FAR/FRR.

curl https://api.indb.tech/api/v2/grain/tiers

В ядре, а не четырьмя SDK: внешний инструмент проверяет изолированный артефакт, Grain — внутри того же конвейера, который принимает, сливает и репликует, с репутацией в момент верификации.

Fusion: память растёт в интеллекте, а не в размере

Повторение — не данные, а паттерн. Три ["home","arrived"] сливаются в одно с fusion_count: 3, а ["alarm","triggered"] в три ночи остаётся отдельной аксиомой. Дедупликация семантическая, DBSCAN, сжатие на тестовых данных 35:1. Быстрый повторный ингест штрафуется, иначе вес сигнала накачивается флудом.

Репутация работает как гравитация:

Mass = Count × Reputation²

Тысяча ботов с репутацией 0.01 даёт массу 0.1, один подписанный сенсор с 0.99 — массу 0.98. Отсюда Reality Guard: 10 000 сообщений «сервер лежит» против одного heartbeat «работает» дают «конфликт данных», и аксиома стоит.

Где это нужнее всего

У агентных систем есть простой: пользователь молчит, лимиты свободны, система не делает ничего. Индустрия предлагает заполнять его саморефлексией — мета-агент читает логи, критик судит воркера, LLM переписывает себе промпты. Не работает: модели с разными паттернами контекста мешают друг другу, координатор сверху даёт тот же испорченный телефон, только дороже по токенам. И главное — рассинхронизация: агент предложил, человек поправил руками и не сказал, агент живёт со своим слепком, контекст оперирует контекстом вместо среды. LLM-критик смотрит на тот же искажённый контекст, который ошибку и породил.

Работает детерминированная сверка состояния с фактами, и модель INDB подходит сюда структурно.

В активном режиме всё летит событиями, а не лентой чата: агент вызвал инструмент → событие, человек поправил файл → событие с более высоким весом источника, API вернул 500 → событие. У каждого место (файл, путь, hermes://…), время и источник с репутацией, ничего не перезаписывается.

В простое ядро делает Exhale: Fusion сжимает повторы и обесценивает неподтверждённые ветки, Echo ищет диссонанс с текущим состоянием места, Deduction находит обрыв цепочки, Prism считает perception_gap, Slice гоняет контрфактуал, не загрязняя основную память. На выходе не новый промпт от агента, а срез: в src/api.py после правки человеком в 14:32 цепочки агента от 14:28 помечены устаревшими, perception_gap = 0.87, обрыв причинной цепочки на событии X.

Это не RAG: векторный кэш при правке файла не знает, что мир изменился, а здесь инвалидация идёт по месту, детерминированно и с подписью. Коннектор — Hermes через MCP. Код в проде INDB не патчит и промпты без человека не переписывает: находит точку рассинхронизации и отдаёт срез правды.

Цифры

Standalone: ингест <1ms, запрос <10ms на тысяче событий. Модули — Prism ~20ms, Echo <30ms, Instinct ~25ms, Deduction <50ms. Кластер из трёх узлов — 99.7% успеха (997 из 1000), латентность 50–250ms, ноль перевыборов лидера за пятиминутный прогон.

Устойчивый throughput кластера — 19–28 событий в секунду. Не опечатка, а цена синхронных коммитов Raft: нужны десятки тысяч вставок — берите профильное решение.

Коэффициенты «прироста качества/стоимости» для LLM x1.25–x1.75 с лендинга — полевые оценки по нашим прогонам, а не воспроизводимый бенчмарк на публичном датасете. Читайте как порядок величины.

Кому подойдёт, а кому нет

Подойдёт, где нужна подписанная история, устойчивая к подделке; где надо доказать присутствие, не раскрывая содержимое; где противоречия показывают, а не схлопывают; где верификация должна терпеть шум. Конкретно — юридические доказательства, медицинские аудит-трейлы, защита источников, IoT с UDP-ингестом, память агентов через MCP.

Не подойдёт при CRUD со стабильной предметной областью: берите Postgres.

Заменой PostgreSQL это не будет, категория другая. И это не open source: ядро проприетарное, API, документация и архитектурные гарантии открыты, self-host через Docker Compose работает. Для части читателей — стоп-фактор, и это нормально.

indb.tech

Автор: Kaaboeld

Источник