ADR-0001: Binding architecture — bridge MVP and native production tier
Статус: принято
Дата: 2026-06-06
Репозиторий: AI-Guiders/pywitdb
Upstream: WitDatabase (OutWit.Database.Core)
Решение (одной фразой)
Двухфазная архитектура: MVP — JSON subprocess bridge через маленький .NET CLI (witdb-bridge); production — NativeAOT C ABI + ctypes с wheels per-platform. Оба тира читают/пишут тот же .witdb; Python API один.
Контекст
- WitDatabase — source of truth для формата
.witdbи ACID semantics (.NET, NuGet). - Python-экосистема (agents, lab, ETL) нуждается в официальном пакете pywitdb (PyPI), не в subprocess-хаках и не в форке формата.
- CascadeIDE / Intercom уже используют
.witdbчерезUseWitDb; cross-lang сценарий: C# пишет store, Python читает. - В репозитории AI-Guiders — отдельный продукт; замена sqlite в CASA — out of scope (отдельный ADR при необходимости).
Цели v0
| API | Семантика |
|---|---|
open(path, password=...) |
Открыть/создать .witdb |
get / put / delete |
KV по bytes-ключам |
transaction() |
ACID batch; rollback on exception |
| context manager | close on exit |
SQL, EF, Studio UI — не в v0.
Рассмотренные варианты
A. JSON subprocess bridge (.NET CLI)
Python spawn witdb-bridge; протокол — newline-delimited JSON (NDJSON) по stdin/stdout.
Плюсы: быстрый MVP; без изменений в WitDatabase Core; контрактные тесты C#↔Python сразу; один CLI для dev/CI.
Минусы: latency; нужен .NET runtime рядом; отдельный процесс на store (или connection pool позже).
B. pythonnet / embedded CLR
Python грузит .NET runtime in-process.
Плюсы: без subprocess overhead.
Минусы: тяжёлая зависимость; fragile wheels; плохой DX на Linux/macOS CI; не цель PyPI «лёгкий pip install».
C. gRPC / HTTP sidecar
Отдельный long-lived .NET service.
Плюсы: масштабирование, remote store позже.
Минусы: overkill для embedded local .witdb; ops burden для v0.
D. NativeAOT C export + ctypes
WitDatabase (upstream PR) экспортирует стабильный C ABI; pywitdb публикует platform wheels.
Плюсы: prod latency; нет .NET в Python-процессе; стандартный путь для Python native extensions.
Минусы: работа в upstream; ABI versioning; matrix win/linux/macOS в CI.
E. Чистый Python reimplementation формата
Отклонено: дублирует source of truth, риск drift от .witdb.
Принятое решение
| Tier | Роль (2026-06) | Статус |
|---|---|---|
| D — Native ctypes | Prod default (backend="auto" → native если DLL/wheel есть) |
✅ win-x64 publish + pytest |
| A — JSON bridge | Dev / CI / fallback (нет native под RID; contract tests без AOT matrix) | ✅ bridge/WitDbBridge |
pythonnet (B) и sidecar (C) — не выбираем.
Prod path дальше: per-RID NativeAOT publish → PyPI wheels; upstream PR OutWit.Database.Native → dmitrat/WitDatabase. Bridge в release не обязателен.
MVP: witdb-bridge CLI
Расположение: bridge/WitDbBridge/ в репо AI-Guiders/pywitdb.
- Target:
net10.0(aligned с Core multi-TFM). - Project ref:
OutWit.Database.Core+BouncyCastle(submodule witdatabase в monorepo). - Один процесс = один open store; Python держит subprocess lifecycle.
Протокол (v1): запрос/ответ — одна JSON-строка на сообщение.
{"id": 1, "op": "open", "path": "store.witdb", "password": null}
{"id": 1, "ok": true}
{"id": 2, "op": "put", "key": "bWV0YTpmdg==", "value": "OTQyNjY="}
{"id": 2, "ok": true}
{"id": 3, "op": "get", "key": "bWV0YTpmdg=="}
{"id": 3, "ok": true, "value": "OTQyNjY=", "found": true}
key/value: base64 bytes.- Ошибки:
{"id": N, "ok": false, "error": {"code": "...", "message": "..."}}. transaction:begin→ ops →commit|rollback(nested не поддерживаем в v0).
Python: pywitdb._bridge (BridgeClient, BridgeDatabase).
Native tier (prod)
- Fork/upstream:
OutWit.Database.Native+include/witdb.h(ADR-0003). - pywitdb:
pywitdb._native+ bundled wheels per RID (CI TBD). open(..., backend="auto"): native first, иначе bridge еслиwitdb-bridgeсобран.
ABI versioning: WITDB_ABI_VERSION в заголовке; pywitdb pin minor at build time.
PyPI и именование
| Решение | Значение |
|---|---|
| PyPI package name | pywitdb (зафиксировано) |
| GitHub | AI-Guiders/pywitdb only |
| Bridge executable | witdb-bridge (shipped as .NET tool or alongside package in bridge/ artifacts) |
Имя witdatabase на PyPI — не используем (коллизия с брендом upstream).
Тестирование и CI
- pytest (Python): unit + integration against bridge.
- Contract fixture (C#): test project пишет
.witdbчерезOutWit.Database.Core; Python читает через pywitdb — тот же файл, те же KV. - CI matrix:
windows-latest,ubuntu-latest(bridge MVP); native tier добавляет per-RID jobs позже.
Последствия
Положительные
- MVP без блокера на upstream PR.
- Один Python API; смена backend прозрачна для callers.
- Cross-lang контракт проверяется в CI до native tier.
Отрицательные / долг
- Bridge требует .NET SDK/runtime в dev и CI.
- Два code path до v1 — поддерживать parity tests.
- Native tier = отдельный трек PR в WitDatabase (не в AI-Guiders org).
Non-goals (повтор)
- Не подменять
agent_field.db/ sqlite в ca-substrate-agent без ADR. - Не тащить EF Core в Python.
- Не дублировать WitDatabase Studio.
План реализации
| # | Задача | Репо |
|---|---|---|
| 1 | Bootstrap pywitdb layout, этот ADR | AI-Guiders/pywitdb |
| 2 | witdb-bridge CLI + NDJSON protocol |
✅ AI-Guiders/pywitdb |
| 3 | pywitdb.open / KV / transaction (bridge + native) |
✅ |
| 4 | C# fixture + pytest contract (T1a/T1b) | ✅ tests/test_contract.py |
| 5 | ADR-0002: provider keys при reopen | ✅ |
| 6 | ADR-0003: C ABI + Native | ✅ fork; upstream PR pending |
| 7 | PyPI wheels: linux-x64, osx-arm64, … | pending |
| 8 | ADR-0004: SQL (WitSQL) для CASA journal | ✅ 0004-sql-layer-and-casa-journal.md → implement |
Ссылки
- Канон-карточка:
knowledge/work/projects/door-to-singularity/pywitdb/README.md - WitDatabase NuGet:
OutWit.Database.Core