Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .claude/plans/d-qr-dirsim-iam-membership-probe-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# D-QR-IAM: typed QR256 relationship composition over dir-sim's borrowed views

**Date:** 2026-10-21. **Status:** LAB-ONLY PLAN / FALSIFIERS, unimplemented. No AD, Entra, Exchange, LDAP or PowerShell writes.

## Hypothesis

**Avoid handrolling derived IAM edges** by compiling already-known identity, predicate, role and group mappings into a small Boolean relational view, with `ClassView` + `WideFieldMask` identifying **eligible stable field positions**, #1659 providing a candidate borrowed global→local register, and #1660 a typed QR256 Bool `OR/AND` fold plus optional cold proof DAG.

The derivation `EffectiveRole(user,role) = EXISTS group: Member(user,group) AND Grant(group,role)` is one test target. `WideFieldMask` DOES NOT itself encode group membership, evidence origin, a group path, identity correspondence or permission. No automatic assumption that equals numeric row ordinal means equals entity across populations.

## Existing ground truth

- `lance-graph-dir-sim/src/lib.rs`: snapshots have independent users/groups 16-bit ordinal spaces (up to 65,536 each) and sparse many-to-many membership, shared version with overlays, Quack selection and simulated execution only.
- `bind.rs::UserBinder` resolves UPN/SMTP to comparison `KeyId` once using existing Quack binding.
- `groups.rs` separates MailEnabled and SecurityEnabled from nesting; mail chains and SID chains have distinct semantics.
- `View::members_transitive[_through]`, `View::groups_transitive` and `actors` are the **independent oracles**, not code to remove before parity is proven.
- `ClassView::fields` (append-only positions) and `WideFieldMask` in contract are the candidate schema geometry. `OrderedLaneWitness` means order must be sealed, not inferred. EXO-46 / #1640 ADMISSION B still apply.

## Contract sketch (not new Rust API)

```text
BoundRelationship {
source_class, target_class, predicate_id,
field_basis: ClassView::fields(...), presence: WideFieldMask,
source_identity: GUID/CodebookWitness, target_identity: GUID/CodebookWitness,
source_order, target_order, snapshot_generation, authority_scope,
method8: BoolCompose, axes: UserLocal8×GroupLocal8 | GroupLocal8×RoleLocal8
}
```

The **QR256 register stores up to 256×256 bits**, not all 65k×65k directory edges at once. Chunked focuses require explicit external-frontier continuation and witnessed remapping. A 64×64 QR64 is 512 B and can serve smaller focuses; never silently drop an external membership.

## Falsifier paths

| Test | Independent reference | Fail condition |
|---|---|---|
| I1 Mapping | stable ClassId + ordered FieldRef and `WideFieldMask` selection; compare `UserBinder` exact UPN/SMTP | unknown field/key or swapped class/ref yields relation anyway |
| I2 One hop | parent group→member, user group→role Boolean existence vs `View`/RBAC oracle | same numerical ordinal used as foreign identity |
| I3 Security chain | nested security groups grant role; existence and complete witness chain match source | a non-security intermediate group unexpectedly transmits permission |
| I4 Mail chain | distinct `MailEnabled` semantics, no SID-derived email permission | an unaddressable group transmits mail |
| I5 Duplicates | Count/BAG matches independent multiset oracle; Bool EXISTS remains idempotent | two supporting paths XOR-cancel or support deletion erases surviving grant |
| I6 Version delta | edit membership, group property or authorization; recompute `BEFORE XOR AFTER` and independent full refresh | stale index, deleted group, old thought incarnation or revoked access still returns authorized true |
| I7 Focus | 256-slot maximum focus with bridges beyond focus, 257th edge external-frontier case | truncated reachability or implicit out-of-scope dereference |
| I8 Cost | direct `View` walk, existing Quack, borrowed co-addressed masks, QR64/QR256; count allocations and source bytes | unprofitable index/materialization promoted as win |

## Execution plan

1. Perform a read-only census of `snapshot.rs`, `view.rs`, `groups.rs`, `actors.rs`, `ogar_rbac::group_policy`; distinguish what's implemented vs planned.
2. Register a prototype typed relationship declaration **outside production directory store**; compile eligible FieldRefs/selection masks through existing contract surfaces.
3. Introduce a bounded borrowed address view with version/authority witness. Do not write an index from a foreign lane's value to select positions in another table; #1640 ADMISSION B forbids this.
4. Evaluate Boolean join/closure via existing mask-risc / ndarray tiles; no new recursive VM, no new permissions engine, and no template-as-string materialization.
5. Verify all positive and counterexample fixtures against `View` and independent multiset reference. If any premise is unknown, return typed UNKNOWN/refusal, not FALSE.
6. Measure 1, 8, 64 and 256 slots, nested depth, 257/external focus, duplicate supports; log cold/index + hot + proof costs separately.
7. Only after parity and permissions, propose cross-domain generalization to actual SAP or HubSPO; NO production IAM changes.

**Explicit non-goals:** no live directory mutation, no group-role schema minting without OGAR evidence, no CE64 encoding change, no privilege inferred from class presence, no new `Edge` heap object, no assumed transitivity for an arbitrary relation.

**References:** [#1659](https://github.com/AdaWorldAPI/lance-graph/pull/1659), [#1660](https://github.com/AdaWorldAPI/lance-graph/pull/1660), [EXO-79](https://linear.app/exo-red/issue/EXO-79), [EXO-86](https://linear.app/exo-red/issue/EXO-86), [EXO-46](https://linear.app/exo-red/issue/EXO-46), [EXO-50](https://linear.app/exo-red/issue/EXO-50).


## Cross-PR ISA/PART_OF zipper experiment

See the [capstone](https://github.com/AdaWorldAPI/lance-graph/blob/research/qr-abi-classview-capstone-20261021/.claude/plans/d-qr-abi-classview-rails-capstone-v1.md). Existing `FacetCascade` already carries six `8:8` pairs after its 4-byte class prefix. Test the *declared* horizontal interpretation `(part_of:u8, is_a:u8)` with 256 local codes/axis against dir-sim's **distinct** `UserOrdinal` and `GroupOrdinal` u16 spaces. The proposed `HHTL16-IsA[16]` and `HHTL16-PartOf[16]` are two separate **logical 16-byte vertical chains**, NOT available 16-byte persisted registers in current code; the existing HHTL nibble path is 16×4-bit, not this 16×8-bit proposal. Compression/fold from global u16 ordinals into local u8 codes must be witnessed and bounded, or return continuation/refusal.

**I9 additional probe:** on a mixed membership/is_a/part_of fixture, preserve typed rules: a subtype does not become a group member, a containment edge does not automatically confer a role, and identity itself does not prove permission. Test 256th vs 257th local entity, cycle, ambiguity, class prefix mismatch, and two distinct global IDs mapped to the same u8. Prefix-composition laws must be separately declared, not inferred from byte adjacency.
Loading