Vyasa KG — ACL (viewer-mask) Engine + UI Handoff Prompt

What to buildURL copied

  1. Generator (gen_kg_index.py): parse the @acl block → emit facts: e=<class> a=kind v=acl_class, e=<role> a=can_see v=@<class> (one per class), e=<person> a=role v=@<role>. The block syntax (already authored):
    • classes=cls_a,cls_b,cls_c
    • grant <role> <class> <class> …
    • person <Full Name> = <role> ← note the = delimiter (names contain spaces).
  1. Query engine (kg_query.py):
    • Make cls fold as a SET (union), not latest-wins scalar — add it to the relation-like union path, or special-case it. (Today it collapses to one class — see bugs.)
    • Add a viewer parameter to the query/Index. Compute closure(can_see(viewer)).
    • Apply the mask as the first operation: drop every fact whose cls set doesn't intersect the viewer's visible classes. A fact with no cls → denied (default-deny).
    • Verify no leak: as role_ext, follow/incoming/diff must never surface an internal/eng fact, even transitively.
  1. UI: add a "View as <role/person>" entry to the existing View dropdown (same surface as State / Open Items / Persona). On select → set viewer → re-render the masked graph. Hidden nodes/edges are silently omitted (default-deny; no tombstone in consumption views). A flat dropdown entry is enough — no nested menu needed.