From b15fae444f690c6a32567c29c63e66dd9e211a95 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 12 May 2026 17:40:23 +0000 Subject: [PATCH 1/3] docs(.claude/SMB): SMB tenant schema reference for cross-session visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lance-graph is the spine; sessions working here don't load smb-office-rs source. Without a local reference, "is this lance-graph change safe for SMB" requires cross-repo zipball + grep every time. These two docs make the SMB shape readable in two pages. Contents: - README.md — when to read, why per-tenant folder, how to extend - SCHEMA.md — the actual reference: - §1: two ontology surfaces (BSON × 14 German; Foundry × 3 English) - §2: Foundry-shape contract that OntologyDto::project(®istry, "SMB", ...) must return (mirrors body PR #355 deleted from upstream) - §3: BSON-shape per-entity required predicates + marking dominance - §4: projection rules Foundry ← BSON, with two flagged gaps (smb.steuer needs kunde_kdnr + eingereicht_am) - §5: lance-graph contracts that affect SMB (which signatures, how) - §6: consumer-side stopgaps that retire when registry hydration lands Pairs with smb-office-rs 611c147 (originating-side OGIT_TTL_INVENTORY) and c204819 (consumer-side stopgap for lance-graph PR #355 break). Per-tenant folder convention; sibling .claude// folders can follow the same shape (MedCare next). --- .claude/SMB/README.md | 31 +++++++++ .claude/SMB/SCHEMA.md | 155 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 .claude/SMB/README.md create mode 100644 .claude/SMB/SCHEMA.md diff --git a/.claude/SMB/README.md b/.claude/SMB/README.md new file mode 100644 index 00000000..48f9a0d7 --- /dev/null +++ b/.claude/SMB/README.md @@ -0,0 +1,31 @@ +# .claude/SMB/ — SMB tenant schema reference + +> **Read this when:** your task in lance-graph touches +> `lance-graph-ontology`, `lance-graph-callcenter::ontology_dto`, +> `lance-graph-callcenter::transcode`, `lance-graph-rbac::policy`, +> the `OntologyRegistry` hydration path, or the registry → DTO +> projection contract — and you need to know what a real tenant +> consumer is shaped like. + +## Files + +| File | Read when | +|---|---| +| `SCHEMA.md` | You're touching a contract that affects SMB consumers. Lists the 14-entity BSON shape, the 3-entity Foundry shape, and the projection rules between them. | + +## Why a per-tenant folder + +The tenant consumer (`AdaWorldAPI/smb-office-rs`) is a separate repo; +this lance-graph workspace doesn't load its source. Without these +reference docs, "is this lance-graph change safe for SMB" requires +cross-repo zipball + grep on every session. With them, the shape is +two pages and immediately readable. + +This is reference material, not policy. Authoritative source is +smb-office-rs. + +## Adding tenants + +If a second tenant lands (MedCare, Stalwart, SAP, future Foundry +consumer), add a sibling folder under `.claude//` with the +same structure. Keep these per-tenant; do not mix shapes. diff --git a/.claude/SMB/SCHEMA.md b/.claude/SMB/SCHEMA.md new file mode 100644 index 00000000..d459e8c1 --- /dev/null +++ b/.claude/SMB/SCHEMA.md @@ -0,0 +1,155 @@ +# SMB tenant — schema reference for lance-graph sessions + +> **Why this folder exists:** lance-graph is the spine; sessions +> working here usually don't have SMB context loaded. When changes to +> `lance-graph-ontology` / `lance-graph-callcenter` / `lance-graph-rbac` +> affect tenant consumers, this folder shows what the SMB tenant +> (`AdaWorldAPI/smb-office-rs`) will hydrate into the registry — so +> upstream changes can be evaluated against a real consumer shape +> without cross-repo grepping. +> +> **Authority:** the source of truth is smb-office-rs: +> - BSON-shape: `crates/smb-ontology/src/{customer,rechnung,mahnung, +> schuldner,woa_artikel,remaining}.rs` +> - Foundry-shape stopgap: `crates/smb-realtime/src/ontology.rs:: +> build_smb_ontology()` +> - Originating inventory: `smb-office-rs/.claude/board/OGIT_TTL_INVENTORY.md` +> +> When the two diverge, smb-office-rs wins; update this doc. + +--- + +## 1. Two ontology surfaces (by design) + +| Surface | Naming | Entity count | Purpose | Where it lives | +|---|---|---|---|---| +| **BSON-shape** | German wire names, `smb.` prefix | 14 | Storage layer; matches C# `db_*.cs` verbatim per smb-office-rs CLAUDE.md iron rule 1 | `smb-ontology` crate | +| **Foundry-shape** | English names, no prefix | 3 | API/membrane layer; what RBAC + RLS + Foundry Object Explorer surface externally | `smb-realtime::ontology` (consumer-side stopgap until OGIT TTL hydrates) | + +Foundry shape is a **projection** of BSON shape. One Foundry `Customer` +projects from one `smb.customer` row. Translation lives in +`smb_bridge::orchestration` (entity_type → table_name). + +--- + +## 2. Foundry-shape — what `OntologyDto::project(®istry, "SMB", …)` must return + +Mirrors the body that lance-graph PR #355 deleted from +`crates/lance-graph-callcenter/src/ontology_dto.rs::smb_ontology()`. +The consumer-side stopgap at `smb-realtime/src/ontology.rs:: +build_smb_ontology()` reproduces it verbatim. + +### Entities (3) + +| Public name | OGIT URI | Required | Optional (Passthrough) | Searchable (CamPq) | Free | +|---|---|---|---|---|---| +| `Customer` | `ogit.SMB:Customer` | `customer_name`, `tax_id` | `address`, `iban` | `industry` | `note` | +| `Invoice` | `ogit.SMB:Invoice` | `invoice_number`, `date`, `total_amount`, `currency`, `customer_ref` | `due_date` | — | `note` | +| `TaxDeclaration` | `ogit.SMB:TaxDeclaration` | `declaration_id`, `tax_year`, `customer_ref`, `declaration_type` | `filing_date`, `status` | — | — | + +### Links (`one_to_many`, 2) + +- `Customer` —`issued`→ `Invoice` +- `Customer` —`filed`→ `TaxDeclaration` + +### Actions (3) + +- `approve` (manual) on `Invoice` → predicate `status` +- `classify` (auto) on `Customer` → predicate `industry` +- `submit` (manual) on `TaxDeclaration` → predicate `status` + +### Label (bilingual) + +- `de` → `Steuerberatungskanzlei` +- `en` → `Tax Practice` + +--- + +## 3. BSON-shape — 14 entities under `smb.*` + +German wire names match C# `db_*.cs` verbatim. Per-property markings +carry GDPR / financial classification. + +| Schema name | Required predicates | Marking dominance | Source | +|---|---|---|---| +| `smb.customer` | `kdnr`, `firma` | Pii on personal, Financial on bank | `customer.rs` | +| `smb.schuldner` | `schuldner_id`, `debtor_name`, `saldo` | Internal/Pii/Financial mix | `schuldner.rs` | +| `smb.rechnung` | `rechnungsnr`, `kunde_kdnr`, `rechnungsdatum`, `faellig_am`, `betrag_netto`, `betrag_brutto`, `ust_betrag`, `ust_satz`, `zahlungsstatus` | Financial on amounts | `rechnung.rs` | +| `smb.mahnung` | `mahnung_id`, `schuldner_id`, `rechnungsnr`, `stufe`, `ausgestellt_am`, `faellig_am`, `gesamtsumme`, `status` | Internal | `mahnung.rs` | +| `smb.dokument` | `dokument_id`, `parent_entity`, `parent_id`, `dateiname`, `mime_type`, `hochgeladen_am` | Internal | `remaining.rs` | +| `smb.bank` | `buchungssatz_id`, `kontonummer`, `buchungsdatum`, `valutadatum`, `betrag`, `waehrung` | Financial | `remaining.rs` | +| `smb.fibu` | `buchung_id`, `buchungsdatum`, `soll_konto`, `haben_konto`, `betrag` | Financial | `remaining.rs` | +| `smb.steuer` | `steuer_id`, `steuerart`, `zeitraum_von`, `zeitraum_bis`, `bemessungsgrundlage`, `steuerbetrag`, `status` | Financial | `remaining.rs` | +| `smb.lieferant` | `lieferant_id`, `firma` | Internal | `remaining.rs` | +| `smb.mitarbeiter` | `mitarbeiter_id`, `vorname`, `nachname` | Pii on personal, Financial on iban | `remaining.rs` | +| `smb.auftrag` | `auftrag_id`, `kunde_kdnr`, `eingegangen_am`, `auftragssumme`, `status` | Internal | `remaining.rs` | +| `smb.angebot` | `angebot_id`, `kunde_kdnr`, `erstellt_am`, `angebotssumme`, `status` | Internal | `remaining.rs` | +| `smb.zahlung` | (see `remaining.rs:503+`) | Financial | `remaining.rs` | +| `smb.artikel` | `beschreibung` | Internal | `woa_artikel.rs` (WoA tenant) | + +All entities also carry `fingerprint` (`CodecRoute::CamPq`) and audit +fields (`ad_create`, `ad_modify`, `ad_delete`). + +--- + +## 4. Projection rules — Foundry shape ← BSON shape + +| Foundry property | BSON source | +|---|---| +| `Customer.customer_name` | `smb.customer.firma` | +| `Customer.tax_id` | `smb.customer.umsatzsteuer_id` (preferred) or `steuernummer` | +| `Customer.address` | `smb.customer.anschrift` (+ `plz` + `ort` + `land` joined) | +| `Customer.iban` | `smb.customer.iban` | +| `Customer.industry` | `smb.customer.branche` | +| `Customer.note` | `smb.customer.notiz` | +| `Invoice.invoice_number` | `smb.rechnung.rechnungsnr` | +| `Invoice.date` | `smb.rechnung.rechnungsdatum` | +| `Invoice.total_amount` | `smb.rechnung.betrag_brutto` | +| `Invoice.currency` | `smb.rechnung.waehrung` | +| `Invoice.customer_ref` | `smb.rechnung.kunde_kdnr` | +| `Invoice.due_date` | `smb.rechnung.faellig_am` | +| `Invoice.note` | `smb.rechnung.notiz` | +| `TaxDeclaration.declaration_id` | `smb.steuer.steuer_id` | +| `TaxDeclaration.tax_year` | derived from `smb.steuer.zeitraum_von` (year part) | +| `TaxDeclaration.customer_ref` | **gap** — `smb.steuer` lacks a customer column; planned: add `kunde_kdnr` | +| `TaxDeclaration.declaration_type` | `smb.steuer.steuerart` | +| `TaxDeclaration.filing_date` | **gap** — `smb.steuer` lacks a filing date column; planned: add `eingereicht_am` | +| `TaxDeclaration.status` | `smb.steuer.status` | + +Both gaps are smb-ontology-side fixes, independent of OGIT TTL. + +--- + +## 5. What lance-graph changes affect SMB + +| Lance-graph change | Affects SMB how | +|---|---| +| `OntologyDto::project(®istry, namespace, …)` signature | `smb-realtime::dto::smb_dto(locale)` calls it for `namespace = "SMB"`. Changes to the projection contract break the consumer. | +| `MappingRow` columns (e.g. PR #355 `IdentityCodec`, `QualiaMeta`) | Computed at hydration; SMB doesn't author them but consumes the projected `OntologyDto` fields. | +| `SchemaExpander` trait | smb-realtime's SPO bridge (`expand_smb_entity`) uses `Ontology::expand_entity`. If SchemaExpander moves to `MappingRow`, smb-realtime adapts. | +| `CachedOntology::new(Ontology)` legacy path | Currently retained for smb-realtime's `smb_cached_ontology()`. If deprecated, smb-realtime needs `CachedOntology::from_registry(&OntologyRegistry, namespace)`. | +| `Policy::evaluate(role, entity, Operation)` | smb-realtime's `SmbMembraneGate` (PR #29) wraps this. Entity keys passed are the Foundry-shape names (`Customer`, `Invoice`, `TaxDeclaration`). | +| `Locale` enum additions | smb-realtime's DTO cache projects every `Locale` eagerly; growing the enum forces cache init updates. | +| TTL hydrator (`hydrate_once_sync`) input format | Decides what OGIT TTL must carry for SMB (see Section 2 for the shape). | + +--- + +## 6. Stale on the consumer side (will retire when registry hydration lands) + +When `OntologyRegistry::hydrate_once_sync(ttl_root)` populates the +`"SMB"` namespace from real OGIT/NTO/SMB TTL: + +- `smb-realtime/src/ontology.rs::build_smb_ontology()` — body deletes, + becomes a thin `OntologyDto::project(®istry, "SMB", …)` facade. +- `smb-realtime/src/dto.rs::cached_smb_ontology() -> &'static Ontology` + — retired when `SchemaExpander` learns to project from `MappingRow`. +- `smb-realtime/src/transcode.rs::smb_cached_ontology()` — retired when + `CachedOntology::from_registry` ships. +- Dual cache path in `smb-realtime/src/spo.rs` (`#[cfg(feature = "postgrest")]`) + — collapses to single path when `dto` becomes unconditional. + +--- + +**Last updated:** 2026-05-12, pairs with smb-office-rs commit `611c147`. +Update when SMB schema changes in smb-ontology or when lance-graph's +registry projection contract shifts. From bf450a0f1b1d1fcaecbad597583f5cd447959b67 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 16:12:40 +0000 Subject: [PATCH 2/3] docs(.claude/SMB): note UnifiedBridge wiring landed in PR #364 + smb-office-rs PR #31 Section 5 row added: lance-graph PR #364 (D-SDR-1..5) shipped the UnifiedBridge + TenantId surface; smb-office-rs PR #31 wired smb_unified_bridge(registry, namespace, role, tenant) -> UnifiedBridge. Currently locked to OgitBridge per-namespace; future SmbBridge (OGIT/NTO/SMB/) drops in via type-param swap with no call-site change. Coexistence framing: the new authorize_read/write/act path is complementary to the legacy SmbMembraneGate / CachedOntology surface. Both stay until SMB TTL hydrates the registry, at which point the legacy hand-rolled Ontology in smb-realtime/src/ontology.rs retires. Footer updated to pin against current main SHAs (lance-graph da156eb, smb-office-rs 074ce9b). --- .claude/SMB/SCHEMA.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.claude/SMB/SCHEMA.md b/.claude/SMB/SCHEMA.md index d459e8c1..e1083501 100644 --- a/.claude/SMB/SCHEMA.md +++ b/.claude/SMB/SCHEMA.md @@ -129,6 +129,7 @@ Both gaps are smb-ontology-side fixes, independent of OGIT TTL. | `SchemaExpander` trait | smb-realtime's SPO bridge (`expand_smb_entity`) uses `Ontology::expand_entity`. If SchemaExpander moves to `MappingRow`, smb-realtime adapts. | | `CachedOntology::new(Ontology)` legacy path | Currently retained for smb-realtime's `smb_cached_ontology()`. If deprecated, smb-realtime needs `CachedOntology::from_registry(&OntologyRegistry, namespace)`. | | `Policy::evaluate(role, entity, Operation)` | smb-realtime's `SmbMembraneGate` (PR #29) wraps this. Entity keys passed are the Foundry-shape names (`Customer`, `Invoice`, `TaxDeclaration`). | +| `UnifiedBridge` + `TenantId` (lance-graph PR #364 D-SDR-1..5) | smb-bridge wired `smb_unified_bridge(registry, namespace, role, tenant) -> UnifiedBridge` per smb-office-rs PR #31. Currently locked to `OgitBridge`; when a dedicated `SmbBridge` (`OGIT/NTO/SMB/` namespace) lands in `lance-graph-ontology::bridges`, the constructor type-param swaps — call sites unchanged. The new `authorize_read/write/act` path is complementary to the legacy `SmbMembraneGate`/`CachedOntology` surface; both coexist until SMB's TTL hydrates the registry. | | `Locale` enum additions | smb-realtime's DTO cache projects every `Locale` eagerly; growing the enum forces cache init updates. | | TTL hydrator (`hydrate_once_sync`) input format | Decides what OGIT TTL must carry for SMB (see Section 2 for the shape). | @@ -150,6 +151,9 @@ When `OntologyRegistry::hydrate_once_sync(ttl_root)` populates the --- -**Last updated:** 2026-05-12, pairs with smb-office-rs commit `611c147`. -Update when SMB schema changes in smb-ontology or when lance-graph's -registry projection contract shifts. +**Last updated:** 2026-05-13, pairs with smb-office-rs main at `074ce9b` +(PRs #29 + #30 + #31 merged: `SmbMembraneGate` + `OGIT_TTL_INVENTORY` + +`UnifiedBridge` wiring) and lance-graph main at `da156eb` +(PR #364 D-SDR-1..5 super-domain + UnifiedBridge surface). Update when +SMB schema changes in smb-ontology or when lance-graph's registry +projection contract shifts. From 83d5219b7c2eff67a9bc45d41342091a5f4b7be2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 16:15:48 +0000 Subject: [PATCH 3/3] docs(.claude/SMB): point at PR #365 W13 hydration spec as the formal companion Sprint-5-6 W13 landed the formal OGIT TTL hydration spec at .claude/specs/pr-ogit-ttl-smb-hydration.md (663 LOC, sourced from smb-office-rs OGIT_TTL_INVENTORY.md). It's the executable handoff for OGIT-side authoring + the lance-graph-side 0-LOC consumption proof. This SCHEMA.md remains the quick-reference (two pages, lance-graph session reader). The W13 spec is the deep-dive when the task is actually authoring OGIT TTL or wiring registry hydration. Header callout added so future lance-graph sessions discover both: SCHEMA.md for quick context, pr-ogit-ttl-smb-hydration.md for execution. --- .claude/SMB/SCHEMA.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.claude/SMB/SCHEMA.md b/.claude/SMB/SCHEMA.md index e1083501..45a0ff9f 100644 --- a/.claude/SMB/SCHEMA.md +++ b/.claude/SMB/SCHEMA.md @@ -15,6 +15,11 @@ > build_smb_ontology()` > - Originating inventory: `smb-office-rs/.claude/board/OGIT_TTL_INVENTORY.md` > +> **Formal hydration spec:** `lance-graph/.claude/specs/pr-ogit-ttl-smb-hydration.md` +> (W13, sprint-5-6) — 35 KB executable spec, derived from the +> originating inventory above. Read this when the task is OGIT-side +> TTL authoring or registry hydration wiring. +> > When the two diverge, smb-office-rs wins; update this doc. ---