feat(rbac): two-axis role charter, P1/P2/P3 invariants, SSOT predicate derivation (TIN-2435)#17
Merged
Conversation
…e derivation (TIN-2435)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Encodes the operator-ratified TIN-2435 design (comment thread, 2026-07-04): two-axis RBAC — governance rank (total order,
ROLE_HIERARCHY) x feature capability (intentional lattice,ROLE_PERMISSIONS). TIN-1606 precedent stands. Version 0.4.0. No npm publish, no Bazel registry release — release acts await the operator.What changed
1.
MEMBER_SELF_SERVICE_COREExported constant defined as
ROLE_PERMISSIONS.memberby construction; pinned by test to the ratified tripleadmin.access,admin.content.view,admin.events.view.2. P2 data reconciliation (view-level grants)
Every role ranked >= member now holds the core. Exact additions:
moderatoradmin.events.vieweditoradmin.events.viewcontributoradmin.events.viewevent_manageradmin.content.view3. Deterministic invariants (replaces the flaky monotonicity property class)
tests/rbac-invariants.test.ts— exhaustive, zero randomness:canManageRole(a,b) === ROLE_HIERARCHY[a] > ROLE_HIERARCHY[b]over all 64 pairs.PERMISSION_FEATURE_DOMAINregistry covers exactly the granted vocabulary (both directions), domains derived fromadmin.<domain>.<verb>.admin.events.manage), admin !> moderator (admin.content.moderate), member !> viewer (admin.analytics.view), and the TIN-1606 pair (contributor never inherits event management).4. Charter as data + docs
ROLE_CHARTER(governance-spine | specialist + rank),FEATURE_DOMAINS,PERMISSION_FEATURE_DOMAIN. Docs:docs/role-charter.md(two-axis model, lattice statement, P1/P2/P3, TIN-1606 precedent, the ratified role x feature charter table — operator-ratified 2026-07-04, TIN-2435) + README charter section +docs/rbac-matrix.mdrefresh.5. Predicate derivation (kills the #628 anti-pattern class)
All hand-maintained role arrays in
core/permissions/index.ts(ALL_ROLES/CONTENT_CREATORS/EDITORS/ADMINS/SUPER_ADMIN+ inline lists, incl.canViewContentandgetAllowedVisibilityOptions) are gone; everycan*predicate derives fromROLE_PERMISSIONS. Full role x predicate matrix locked cell-by-cell in tests.New permission strings (vocabulary additions so non-mapping predicates derive from data instead of arrays; none granted to
member, so the core stays the ratified triple):admin.content.publishcanCreatePublicContent, visibilitypublictieradmin.content.media_createcanCreateVideosadmin.content.deletecanDeletePosts/canDeleteVideos/canDeleteContent, visibilityadmintieradmin.events.deletecanDeleteEventsIntentional predicate deltas (P2 member-core flow-through; every other cell is behavior-identical to the pre-derivation arrays):
canCreateEventscanCreateEventscanCreateEventscanDeleteOwnContentDesign notes / judgment calls
canViewEvents = hasPermission(role,'admin.events.view')would flipviewer'scanViewEventstrue→false (viewer is below the member floor and holds noevents.view). Per the explicit behavior-identity constraint, the all-roles list-view predicates (canViewPosts/canViewEvents/canViewProfiles/canViewVideos/canEditOwnProfile) derive fromadmin.accessinstead, which is set-identical to the historicalALL_ROLESbehavior. If viewer should lose list-view access, that is a one-line ratification away.event_managerto holdadmin.content.view, so post-reconciliationevent_managerIS a superset ofcontributor. The TIN-1606 non-nesting survives in the contributor-does-not-inherit-events direction and as the general specialist principle; the old test assertingevent_managerlackscontent.viewwas updated accordingly.Verification
tsc --noEmitclean;publintclean.>→>=⇒ red), P2 (editor losesevents.view⇒ red), P3 (unregisteradmin.events.delete⇒ red); reverted ⇒ green.Companion backport: tinyland.dev PR (vendored test-layer + P2 data mirror, interim until TIN-1721).