|
| 1 | +## 2026-06-23 — E-AUTH-CLASS-WIRED-TO-RBAC — the OGIT-imported 0x0B AuthStore family is now the membrane front-door of authorize() |
| 2 | + |
| 3 | +**Status:** FINDING (2026-06-23). The OGIT `NTO/Auth/Configuration` entity (arago's |
| 4 | +`auth_store`, 1:1 with OGAR `0x0B01`) is wired into `lance-graph-rbac` as the |
| 5 | +authorization membrane (keystone §7 / I-K7: the inner `authorize()` kernel never |
| 6 | +touches a token). `lance-graph-rbac/src/auth.rs`: |
| 7 | + |
| 8 | +- `AuthProvider` enum = the preminted `0x0B` family (`Store`/`Zitadel`/`Zanzibar`/ |
| 9 | + `OryKeto`); each variant's classid is resolved through the **zero-dep contract |
| 10 | + mirror** (`contract::ogar_codebook::canonical_concept_id`) — one source, no |
| 11 | + hardcoded `0x0B0N`, no `ogar-vocab` dep (BBB-safe). |
| 12 | +- `ClaimGrammar` per provider (subject/roles/tenant claim keys) — Zitadel's |
| 13 | + project-roles URN, Zanzibar's user/relation/namespace tuple grammar, the |
| 14 | + plain-OIDC base — the §7 "each profile carries its claim grammar as data". |
| 15 | +- `AuthProvider::resolve(sub, roles, tenant) -> ResolvedIdentity` — the §7 mapping |
| 16 | + (`sub → actor`, `role-key → roles`, `org → tenant`/scope). `ResolvedIdentity` is |
| 17 | + the ONLY thing that crosses inward; it feeds `authorize(rbac, &id.actor, class, op)`. |
| 18 | +- 4 tests incl. `resolved_identity_feeds_authorize` (membrane → kernel end-to-end) |
| 19 | + and `provider_class_ids_resolve_through_the_contract_mirror` (pins the 0x0B family |
| 20 | + to the codebook). |
| 21 | + |
| 22 | +Token *extraction* (JWT/JSON parse via `grammar()`) stays at the consumer membrane — |
| 23 | +no JWT/serde dep leaks into the rbac tier. The consumer maps IdP role strings → its |
| 24 | +own role set. Cross-ref: OGAR `CLASSID-RBAC-KEYSTONE-SPEC.md` §7, E-RBAC-AUTHORIZE-PROBE-GREEN. |
| 25 | + |
| 26 | +## 2026-06-23 — E-RBAC-AUTHORIZE-PROBE-GREEN — classid-keyed `authorize()` reproduces the shipped membrane gate bit-for-bit; keystone §5 promoted CONJECTURE→FINDING (for the in-repo reference) |
| 27 | + |
| 28 | +**Status:** FINDING (probe green, 2026-06-23). The OGAR `CLASSID-RBAC-KEYSTONE-SPEC.md` |
| 29 | +§10 names `PROBE-OGAR-RBAC-AUTHORIZE` as the gate that must pass before any consumer |
| 30 | +collapses onto classid-keyed authorization: the classid-keyed kernel must reproduce a |
| 31 | +reference system's decision **bit-for-bit**. Built against the in-repo reference (the |
| 32 | +shipped `lance_graph_rbac::policy::Policy::evaluate` — the "reconcile the shipped |
| 33 | +MembraneGate path with the keystone" framing of `ISS-RBAC-AUTHORIZE-BY-CLASSID`): |
| 34 | + |
| 35 | +- `lance-graph-rbac/src/authorize.rs` — `ClassRbac` trait (§4), `authorize(rbac, actor, |
| 36 | + class: ClassId, op)` (§5 positive ∧ op-gate kernel), `ClassGrants` (`PermissionSpec` |
| 37 | + **re-keyed by `ClassId`**, §11). The kernel mirrors the shipped deny reasons exactly |
| 38 | + ("unknown role" / "insufficient read depth" / "predicate not writable" / "action not |
| 39 | + allowed") so the comparison is bit-for-bit, not just allow/deny. |
| 40 | +- `probe_ogar_rbac_authorize` — 15-tuple corpus across all three SMB roles, all three op |
| 41 | + kinds, the allow path, every distinct deny reason, the depth boundary, and the |
| 42 | + unknown-actor path → all equal to `Policy::evaluate`. GREEN. |
| 43 | +- `probe_is_falsifiable_under_wrong_keying` — proves the gate is not vacuous: a wrong |
| 44 | + classid flips an Allow, so the corpus genuinely tests the keying + kernel, not a |
| 45 | + delegation. |
| 46 | + |
| 47 | +**Honest fence (what is NOT yet certified):** the shipped reference is positive |
| 48 | +role→permission only — no row-scope predicate, no field projection in the decision. So |
| 49 | +this gate certifies the §5 *positive ∧ op-gate* half and the §11 classid re-keying. |
| 50 | +The §5 stage-2 row-scope predicate and the projecting `Allow { scope, mask }` return |
| 51 | +remain keystone work; the stronger references (Odoo `ir.model.access ∧ ir.rule`, |
| 52 | +OpenFGA) exercise scope and are the follow-on probes. **Necessary, not yet sufficient** |
| 53 | +for the full keystone — but it is the step-4 reconciliation, and it unblocks the |
| 54 | +medcare #169 consumer-collapse (`authorize(actor, HealthcarePort::class_id("Patient"))`) |
| 55 | +against the positive-grant half. Trait promotion to `lance-graph-contract` (§11) and the |
| 56 | +scope-bearing references are the next deliverables. |
| 57 | + |
| 58 | +## 2026-06-23 — E-CODEBOOK-MINT-IS-A-CROSS-REPO-ARC — an OGAR concept mint is NOT done until the lance-graph-contract mirror lands in the SAME arc |
| 59 | + |
| 60 | +**Status:** FINDING (cross-repo cascade, 2026-06-23). Minting the `0x0B` |
| 61 | +AuthStore family in OGAR (`ogar-vocab` PR #110, merged to OGAR `main`) added 4 |
| 62 | +concepts to `ogar_vocab::class_ids::ALL` (39 → 43). The `lance-graph-contract` |
| 63 | +zero-dep mirror (`ogar_codebook::CODEBOOK`) was NOT updated in the same arc, so |
| 64 | +the **compile-time `COUNT_FUSE`** in `lance-graph-ogar` (`assert!(mirror::CODEBOOK.len() |
| 65 | +== ogar_vocab::class_ids::ALL.len())`) fired `error[E0080]` in **every** lance-graph |
| 66 | +consumer that vendors the OGAR git dep — medcare CI went red on a `cargo build`, |
| 67 | +not just a test. The fuse did exactly its job; the gap was process. |
| 68 | + |
| 69 | +The lesson, promoted to a rule: |
| 70 | + |
| 71 | +1. **The codebook has TWO authoritative homes that move in lockstep.** OGAR |
| 72 | + `ogar-vocab` (the source) and `lance-graph-contract::ogar_codebook` (the |
| 73 | + zero-dep wire mirror). The `COUNT_FUSE` (compile-time) + `assert_codebook_parity` |
| 74 | + (runtime, in `lance-graph-ogar`) bind them. A mint touches BOTH or it breaks |
| 75 | + the build of everything downstream. |
| 76 | +2. **A mint is a cross-repo arc, not a single-repo PR.** The Definition-of-Done |
| 77 | + for "mint concept X in OGAR" includes: (a) the OGAR `ogar-vocab` entry + |
| 78 | + `ConceptDomain` variant + `canonical_concept_domain` arm; (b) the paired |
| 79 | + `lance-graph-contract` mirror CODEBOOK rows + `ConceptDomain::X` variant + |
| 80 | + `0xDD => X` arm; (c) the `lance-graph-ogar` `domains_agree` match arm (else the |
| 81 | + runtime parity test panics); (d) the consumer coverage gates that inherit the |
| 82 | + concept set (medcare's RLS fail-closed gate inherits the Health set this way — |
| 83 | + a new Health concept becomes a fail-closed boot error, by design). |
| 84 | +3. **Fix landed here:** mirror CODEBOOK +4 auth rows (auth_store 0x0B01, |
| 85 | + auth_zitadel 0x0B02, auth_zanzibar 0x0B03, auth_ory_keto 0x0B04), |
| 86 | + `ConceptDomain::Auth`, `0x0B => Auth`, and the `domains_agree` `(O::Auth, C::Auth)` |
| 87 | + arm — restoring 43 == 43. Confirmed by the OGIT Configuration ⊨ auth_store |
| 88 | + convergence (arago's Jan-2026 bridge entity). See OGAR `docs/CLASSID-RBAC-KEYSTONE-SPEC.md` |
| 89 | + §7 + OGAR `EPIPHANIES` for the mint provenance. |
1 | 90 | ## 2026-06-23 — E-DOLCE-ODOO-SILENT-SUFFIX-DRIFT — two hydrator-side suffix rules silently failed their own comments; cross-validation against `od_ontology::alignment` caught it (odoo-rs PR #15) |
2 | 91 |
|
3 | 92 | **Status:** FINDING (cross-validation result from a sibling repo). Two |
|
0 commit comments