Reported March 2026
Notionhash table

Page Permission Inheritance

Reported by candidates from Notion's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Notion OA. Under 2s to a working solution.
Founder's read

Notion's March 2026 OA hands you a permissions puzzle that looks like a design question but isn't. Strip the story and it's a tree walk with a max. For one page, collect every permission on it and its ancestors, expand groups into users, and keep the highest role per user. Then print everyone above NONE in sorted order. If you've got an invite for the next day or two, this is the shape to expect. StealthCoder sits invisibly on your screen as a safety net if you blank mid-assessment, but the logic below is short enough to hold in your head.

The problem

Permission roles have this increasing order: NONE < VIEW < COMMENT < EDIT. Pages form a rooted forest. Each pageParents row is [pageId, parentId], with - for a root.
A user can receive a role directly through [pageId, userId, role] in userPermissions, or through a group. Each group membership is [groupId, userId], and each group permission is [pageId, groupId, role].
A permission applies to its page and every descendant. A user's effective role on pageId is the most permissive role from every direct or group permission on that page or an ancestor.
Return two strings:
the effective role for the requested userId;
every user named by either permission input whose effective role is above NONE, formatted as userId:role in lexicographic user-ID order and joined by commas, or the empty string when no user qualifies.

Function
resolvePagePermissions(pageParents: String[][], userPermissions: String[][], groupMemberships: String[][], groupPermissions: String[][], pageId: String, userId: String) → String[]

Examples
Example 1
pageParents = [["root","-"],["child","root"]]
userPermissions = [["root","alice","VIEW"],["child","bob","COMMENT"]]
groupMemberships = [["editors","carol"],["editors","alice"]]
groupPermissions = [["child","editors","EDIT"]]
pageId = "child"
userId = "alice"
return = ["EDIT","alice:EDIT,bob:COMMENT,carol:EDIT"]
Alice inherits VIEW from root and receives EDIT from the child page through editors, so EDIT wins. The second row lists every user with a non-NONE effective role in user-ID order.

Constraints
1 <= pageParents.length <= 500.
Every page appears once, parent references are valid, and the page hierarchy has no cycle.
0 <= userPermissions.length, groupMemberships.length, groupPermissions.length <= 2000.
IDs are non-empty ASCII strings containing neither a comma, colon, nor whitespace.
Every role is one of NONE, VIEW, COMMENT, or EDIT.
The requested page exists; the requested user need not appear in the permission data.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick is to flip the question. Don't compute each user's role by climbing the tree. Climb once from pageId to the root and build the set of ancestor pages, including the page itself. Then scan userPermissions and groupPermissions, keep only rows whose page is in that set, and fold them into a map of user to max role. For group rows, expand through a groupId to members map. Rank roles as NONE 0, VIEW 1, COMMENT 2, EDIT 3 and compare numbers, never strings. The pitfalls: forgetting users who appear only through a group, dropping NONE rows incorrectly, and sorting by role instead of user ID. A user named only with NONE shouldn't appear in the second string. The requested user defaults to NONE if absent. StealthCoder is the hedge if you freeze on the output format during the live OA. Total work is roughly linear in the input sizes plus a sort.

Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.

If this hits your live OA

You can drill Page Permission Inheritance cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.

Get StealthCoder

Related leaked OAs

⏵ The honest play

You've seen the question. Make sure you actually pass Notion's OA.

Notion reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Page Permission Inheritance FAQ

What's the real trick in the Notion page permission problem?+

Walk up from the requested page once to collect its ancestors, including itself. Then only permissions on those pages matter. Fold direct and group grants into a map of user to highest role. The tree part is tiny, the rest is bookkeeping with a max.

How hard is this one really?+

Easy to medium. No fancy algorithm is needed. The difficulty is handling several inputs cleanly: groups, ancestors, NONE roles, and sorted output. Constraints are small, so a simple map-based solution runs fine.

How should I represent the roles?+

Map them to integers: NONE 0, VIEW 1, COMMENT 2, EDIT 3. Compare and take the max numerically, then map back to a string for output. Comparing role strings alphabetically gives the wrong order, so avoid it.

What edge cases break most solutions?+

Users who appear only via group permissions, users with only NONE grants who must be excluded from the list, a requested user missing from all data (answer NONE), and empty results returning an empty string. Also sort user IDs lexicographically, not by role.

How do I prepare for this in 48 hours?+

Write it once from scratch with the example from the problem. Practice building a parent map, climbing to the root, and merging maps with a max. Then test empty inputs. Tree-plus-aggregation problems like this reward clean structure over cleverness.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Notion.

OA at Notion?
Invisible during screen share
Get it