docs(frontend): revise permission/persona spec pages - #1263
docs(frontend): revise permission/persona spec pages#1263manishdixitlfx wants to merge 12 commits into
Conversation
Adopt permission-not-persona throughout both spec pages: add a Core Principle section, define auditor vs viewer terminology (per Eric Searcy's June 25/26 review) and apply it consistently, resolve the Board Member/Contributor context-entry ambiguity Eric flagged as his most important feedback, remove the ED persona-guard carve-out for writer actions, and reword the P0 API-enforcement gate per his "UI guards are degradation, not enforcement" note. Fact-check the current-status sections: PR #1130 and #1193 have shipped; LFXV2-2753 was rescoped 2026-07-19 and is now Discarded, not in progress; the ED fast path in writer.guard.ts and newsletter-access.guard.ts still grants write, which PERMISSIONS.md suggests is a bug rather than a deliberate model choice. Add a Model Asks section for the platform team covering ED-relation removal and LF Staff Team org-lens inheritance. LFXV2-2913 Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughTwo architecture documents define permission-based navigation and authorization for Me, Foundation, Project, and Discovery flows. They separate context access, action authority, persona presentation, discovery, defaulting, edge cases, implementation priorities, and operational metrics. ChangesPermission and Persona Navigation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Revises the frontend permission/persona specifications to make permissions authoritative and personas presentation-only.
Changes:
- Defines selector, discovery, and contextual writer rules.
- Adds persona scenarios, defaulting logic, platform-model questions, and operational metrics.
- Updates status references for shipped permission work.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 13 comments.
| File | Description |
|---|---|
permission-persona-navigation-model-preread.md |
Expands the target permission and navigation model. |
permission-persona-decision-matrix.md |
Adds detailed permission and persona scenarios. |
Comments suppressed due to low confidence (2)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:321
- Steps 4 and 5 select from the same auditor/role-permitted set, so step 5 is unreachable and step 4 has no deterministic tie-breaker. This conflicts with the examples and acceptance text that require stable selection. Collapse each permission tier into an explicitly stable choice.
3. Choose a project where the user has a writer/manage grant.
4. Choose a project where the user has an auditor/explicit role grant.
5. Choose first grant-permitted project in stable sort order.
docs/architecture/frontend/permission-persona-decision-matrix.md:72
- This defaulting chain lists an auditor/explicit-role choice and then a first grant-permitted choice, but those are the same candidate set. The latter branch can never run, while the former does not define how to choose among multiple grants. Match the stated stable-order contract by applying the stable tie-break within each permission tier.
- **Default order:** Existing selected project (if still auditor/role-permitted), last selected valid project (if still auditor/role-permitted), project with a writer/manage grant, project with an auditor/explicit role grant, first grant-permitted project in stable sort order, none -> stay in Me/discovery.
PR SummaryLow Risk Overview The navigation preread grows from a short meeting note into a full working spec: auditor (not legacy “view”) for Foundation/Project selector and context entry; action-specific permissions ( Adds Reviewed by Cursor Bugbot for commit 495a3ff. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/architecture/frontend/permission-persona-navigation-model-preread.md`:
- Around line 302-322: Define a deterministic stable-sort tie-breaker for
equal-priority writer/manage and auditor/explicit-role candidates in the
foundation and project defaulting orders in
docs/architecture/frontend/permission-persona-navigation-model-preread.md:302-322,
then apply the identical ordering rule to the corresponding decision matrix
entries in
docs/architecture/frontend/permission-persona-decision-matrix.md:58-74. Preserve
the existing priority order and fallback behavior while ensuring API ordering
cannot change the selected context.
- Around line 168-184: Align the documentation and implementation guidance so
persona-only signals never grant Foundation/Project context entry: in
docs/architecture/frontend/permission-persona-navigation-model-preread.md:168-184,
state that only ED is a real relation and writer/auditor grants remain
independent authorization inputs; in
docs/architecture/frontend/permission-persona-decision-matrix.md:60-74, require
selector eligibility to ignore persona-role inputs; and at :151-154 and
:187-189, add explicit regression cases preserving the Board Member and
Contributor caveats.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 07272d0f-98ee-4fdc-ac55-d1e1bbb6575d
📒 Files selected for processing (2)
docs/architecture/frontend/permission-persona-decision-matrix.mddocs/architecture/frontend/permission-persona-navigation-model-preread.md
- Fix internal contradiction between Core Principle ("never branch on
role or persona") and the TL;DR/sidebar text implying role-based
branching. Distinguish access decisions (permission only) from
presentation decisions (persona allowed).
- Rename "Role pairs" to "Persona pairs" and narrow the "not discrete
roles anywhere in LFX data" claim: Maintainer is a discrete value in
CDP role data, just not an FGA relation (verified against
persona-detection.service.ts).
- Correct the ED-relation write-capability claim: executive_director
does inherit campaign_manager (write, Campaigns) in addition to
auditor/marketing_auditor (read) per the live model.fga -
PERMISSIONS.md's rendered table simply omits those rows. Rework the
Model Asks ED-removal question to account for every affected ED
losing marketing_auditor/campaign_manager, not just the one non-staff
exception, and surface the live tension between Eric Searcy's "should
probably be removed" and LFXV2-2236 building around keeping the
relation.
- Reconcile "ED-shaped pages" with LFXV2-2236 (in review): Campaigns
and Marketing Impact are migrating to named capabilities
(campaign_manager/marketing_auditor); Health Metrics stays
intentionally ED-gated. Confirmed via app.routes.ts /
executive-director.guard.ts that main still gates all three on
persona alone.
- Fix Me-lens and decision-matrix create/meeting rules that assumed
Foundation/Project writer as the only path: the shipped picker also
authorizes committee.writer (meetings/surveys/votes) and
project.meeting_coordinator (meetings), per writer.guard.ts.
- Make cold-start defaulting deterministic: embed the stable-sort
tie-breaker inside each grant tier instead of a separate unreachable
tier, in both docs.
- Add explicit regression-case bullets for the Board Member/Contributor
no-grant caveats in the decision matrix.
LFXV2-2913
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (10)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:57
- The model does not define
vieweras discoverability-only across resource types. Current permissions allow viewer-level access to data such as project documents and meeting registrants/RSVPs, so this definition would cause later designs to apply the wrong relation to reads. Describe viewer as resource-specific read eligibility and reserve auditor for each resource's privileged scope.
- **Viewer** — discoverability only. You can tell the thing exists (a public
meeting, an active project) but you do not get access to what is inside it
(participants, formation-stage child projects, private documents). Viewer
is not ordinarily assigned directly: it is conditional on object attributes
(public/conditional) or inherited from another role you hold (a committee
docs/architecture/frontend/permission-persona-navigation-model-preread.md:226
- This formula omits the existing
project.meeting_coordinatorandcommittee.writerpaths documented above and implemented bywriterGuard. If the target change is followed literally, removing the ED branch would also regress legitimate meeting coordinators and committee writers. Express the change as retaining the resolved target's action-specific grant while removing only the persona shortcut.
Current writerGuard = Executive Director fast path or canWrite()
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-navigation-model-preread.md:235
- This embeds transient workflow state (
in review) in an architecture document; the same pattern recurs for LFXV2-2236/LFXV2-2726 below.docs/reviews/docs-checklist.md§4 requires replacing status trackers because they silently go stale. Keep the ticket IDs and durable dependency/current-code facts, but remove nonterminal states such as “in review” and “not yet started.”
This migration is tracked in LFXV2-2236 ("Add Marketing Ops UI access (FGA guards)," in review as of this writing) — today, all three pages on `main` still gate solely on `executiveDirectorGuard` (a pure persona check with no FGA lookup). Until that ticket merges, treat "Current UI Facts" as describing the actual state, not this target state.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:461
- The current model has additional non-
marketing_opspaths tomarketing_auditor: a direct[team#member]assignment and inheritance from a parent project'smarketing_auditor. Onlycampaign_manageris exclusively ED-or-marketing-ops. Consequently, removing ED does not drop Marketing Impact from every non-marketing-ops ED; the impact analysis must distinguish users who retain one of those other read paths.
- It is also, today, the sole non-`marketing_ops` path to
`marketing_auditor` (read) and `campaign_manager` (write) — removing
`executive_director` outright would silently drop marketing dashboard
and Campaigns capability for **every** ED who is not separately on the
`marketing_ops` team, not just the one non-staff exception. This has to
docs/architecture/frontend/permission-persona-navigation-model-preread.md:107
- Documents are not covered by either named guard:
DOCUMENT_ROUTESuses onlyauthGuard, andDocumentsDashboardComponent.canUploadcurrently checks only that the page is project-scoped. Including documents in this ED-fast-path inventory is therefore factually wrong and hides a separate permission-affordance gap from the planned remediation.
This issue also appears on line 225 of the same file.
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main` — both grant **write** access unconditionally to ED persona, covering meetings, votes, surveys, mailing lists, newsletters, and documents. The `executive_director` relation does carry one write-capable inheritance today — `campaign_manager`, scoped to the Campaigns feature (see Model Asks below) — but it does not inherit project `writer`, and none of the general write actions these two guards protect are backed by any ED-inherited relation. `PERMISSIONS.md`'s rendered Project table only shows `Executive Director` in view/read rows because it does not render the marketing/campaign relations at all, not because those relations don't exist in the live model (`model.fga`). Granting general project write through this fast path is very likely a bug, not a deliberate model choice, and is tracked separately for removal rather than treated as an open design question.
docs/architecture/frontend/permission-persona-decision-matrix.md:56
- This top-level Me rule excludes the committee/group targets and meeting-coordinator grant that the same matrix explicitly supports at line 98. As written, it gives implementers conflicting requirements for valid create flows.
- **Create/manage rule:** Allowed only after the action resolves or asks for a target Foundation/Project context and writer permission passes.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:233
- Keeping Health Metrics ED-persona-gated contradicts this spec's absolute rule that persona never decides whether a route opens or data is readable (Core Principle lines 32-39 and the companion matrix lines 113-116). The current
executiveDirectorGuardis explicitly a pure persona check, so the target must either introduce/check a named Health Metrics capability (potentially inherited by ED/LF Staff) or clearly revise the core contract to define this exception.
This issue also appears on line 235 of the same file.
- **Health Metrics** is the one page intended to stay ED-gated by design, not migrated to a shared capability.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:9
- “Explicit role grant” is never defined, so the selector contract is not implementable. In the current project model, owner/writer/ED already inherit
auditor, whilemeeting_coordinatoris an explicit relation that does not; this wording therefore either adds nothing or admits meeting coordinators to contexts whose privileged read permission they lack. Specify the exact qualifying relations, or makeproject#auditorthe single capability checked for context entry.
This issue also appears on line 53 of the same file.
- **Where can I go?** An auditor or explicit role grant controls Foundation/Project context eligibility.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:232
- This inheritance list omits the model's direct
[team#member]assignment path formarketing_auditor. Since this section defines who the new capability guard should admit, leaving that path out makes the target behavior narrower than the actual FGA relation.
This issue also appears on line 457 of the same file.
- **Marketing Impact** should check `marketing_auditor` (read-only, inherited from `executive_director`, `marketing_ops`, or a parent project).
docs/architecture/frontend/permission-persona-decision-matrix.md:12
- This global rule excludes legitimate viewer-level reads. In the current model, many object details are intentionally guarded by resource
viewer(for example project documents and meeting details/registrants), while auditor is reserved for more privileged reads. Define page/data visibility as the resource-specific read capability rather than defaulting every read to auditor or an explicit role.
Data/page visibility -> permission (auditor/explicit role or named capability)
The Jul 29 Copilot review flagged that the ED-relation discussion argued a position (keep vs. remove) instead of stating what the app checks. Reframe per the app's own principle: it gates on named permissions, never on which relation bundles them, so bundling is the platform team's call, not this document's. - Current UI Facts: narrow the writer.guard.ts/newsletter-access.guard.ts bug description - ED does not inherit project writer, but the model does route marketing_auditor/campaign_manager through executive_director, which PERMISSIONS.md's rendered table omits. - Writer Actions: delete the "open model decision" framing (invented foundation_insights_viewer vs. open-to-auditors). State plainly that Campaigns/Marketing Impact gate on the existing campaign_manager/ marketing_auditor permissions and Health Metrics stays ED-gated by design (LFXV2-2236, in review) - no new capability needed, no reference to executive_director from app code. - Model Asks #1: replace "removal is acceptable provided..." and the Eric-vs-LFXV2-2236 tension framing with a neutral permission-bundling ask - the app checks auditor/writer/marketing_auditor/campaign_manager directly; the platform team may keep, rename, or remove executive_director as long as every affected user (the one non-staff ED, and the marketing permission edges for every ED) keeps those permissions through some bundle. - Generalize the Me-lens rule blocks and the matching decision-matrix sections (Create Action From Me, Existing Item Action From Me, Meetings) from "target Foundation/Project + writer permission" to "resolved target object (project, foundation, committee, group) + the action-specific grant on that object," matching PERMISSIONS.md's actual Scheduled Meeting Organizer inheritance (Project Writer, Project Meeting Coordinator, Committee Writer). Verified the Core Principle contradiction, role/persona terminology, "not discrete roles" overclaim, and defaulting-ladder determinism findings from the same review were already fixed by the prior fix(review) commit; CodeRabbit confirmed both of its findings resolved. LFXV2-2913 Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/architecture/frontend/permission-persona-decision-matrix.md`:
- Line 90: Update the permission description near the “Required permission”
entry to distinguish target types: use writer permission for Foundation/Project
targets, committee writer for committee or group targets, and scope
project.meeting_coordinator exclusively to meeting actions. Align the wording
with the existing authorization rules referenced by the committee.writer and
project.meeting_coordinator definitions.
- Line 212: Update the meeting “Create/manage” permission contract to match
writerGuard’s implemented executive-director behavior: either remove the
executive-director fast path from writerGuard so contextual organizer-granting
relations are always required, or explicitly add ED as an exception here and in
the downstream permission contract; keep the documented Project/Foundation
Writer, Project Meeting Coordinator, and Committee Writer rules aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8f2dd56c-62dd-4be2-8984-6eab29199d73
📒 Files selected for processing (2)
docs/architecture/frontend/permission-persona-decision-matrix.mddocs/architecture/frontend/permission-persona-navigation-model-preread.md
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/architecture/frontend/permission-persona-navigation-model-preread.md
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (10)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:229
- This target-state formula drops the guard's existing action-specific paths.
ProjectContextService.canWrite()checks onlyproject.writer, whilewriterGuardalso admitsproject.meetingCoordinatorfor meetings andcommittee.writerfor meetings, surveys, and votes. Implementing the documented target would regress those authorized users; describe retaining the action-specific grant check and removing only the ED fast path.
Current writerGuard = Executive Director fast path or canWrite()
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-decision-matrix.md:90
- This scopes both alternatives to committee/group targets, but
meeting_coordinatoris a Project relation; onlycommittee.writerapplies when the target is a committee/group. The Create Action section correctly distinguishes these cases, so this existing-item rule should do the same to avoid an impossible permission lookup.
- **Required permission:** Viewer/discoverable eligibility or item eligibility for read actions. The action-specific grant on the item's resolved target object for write actions — writer permission for a Foundation/Project target, or committee writer / meeting coordinator when the target resolves to a committee or group.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:238
- “In review as of this writing” is ephemeral ticket-state tracking and will become false without a code or architecture change. Per
docs/reviews/docs-checklist.md:33-49, retain the current implementation summary and ticket link, but omit the mutable workflow status.
None of these three needs a new capability invented for it — the permissions already exist in the model. This migration is tracked in LFXV2-2236 ("Add Marketing Ops UI access (FGA guards)," in review as of this writing) — today, all three pages on `main` still gate solely on `executiveDirectorGuard` (a pure persona check with no FGA lookup). Until that ticket merges, treat "Current UI Facts" as describing the actual state, not this target state.
docs/architecture/frontend/permission-persona-decision-matrix.md:364
- The direct-URL edge case again narrows authorization to contextual writer, so it conflicts with the documented committee-writer and meeting-coordinator routes. A direct meeting/survey/vote URL must run the same action-specific target check as the picker and
writerGuard; otherwise valid committee writers and meeting coordinators are specified to fail closed.
- **Required permission:** Resolved target context plus writer permission.
- **Destination:** Requested route only if writer check passes.
- **Allowed actions:** Continue if authorized.
- **Denied actions:** Redirect or fail closed if target context is missing or writer permission fails.
docs/architecture/frontend/permission-persona-decision-matrix.md:56
- This still limits Me creates to Foundation/Project writer access, contradicting the corrected Create Action section below and the shipped committee/group target path. Meetings, surveys, and votes may use
committee.writer, and meetings may useproject.meeting_coordinator, so the top-level Me rule must preserve action-specific targets and grants.
This issue also appears in the following locations of the same file:
- line 90
- line 361
- **Create/manage rule:** Allowed only after the action resolves or asks for a target Foundation/Project context and writer permission passes.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:161
- These examples revert from the action-specific contract above to generic context writer/viewer checks. Scheduled-meeting management follows the organizer-granting relation (which can come from meeting coordinator or committee writer), and vote/survey results have a distinct results-viewer permission rather than following ordinary viewer/discoverability. As written, implementers could deny valid meeting managers or expose results under the wrong read check.
This issue also appears on line 228 of the same file.
- **Pending agenda action:** resolve the target group/project/foundation; allow agenda management only if writer permission applies.
- **Meeting card:** open the meeting with its context; edit/manage only if writer permission applies.
- **Vote or survey:** open the item; view/results follow viewer/discoverable eligibility for that item, edit/close follows writer permission.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:9
- Making an “explicit role grant” an independent context-entry authority contradicts the key/core contract below that application code never branches on roles and consumes capabilities instead. It is also materially ambiguous: the live model's
meeting_coordinatoris an explicit Project role that inheritsviewer, notauditor, so this wording does not say whether it should open the full Project context. Define selector eligibility as a named capability (for example, auditor inherited through qualifying roles), or model a separate context-entry capability, rather than treating an unspecified role grant as permission.
- **Where can I go?** An auditor or explicit role grant controls Foundation/Project context eligibility.
docs/architecture/frontend/permission-persona-decision-matrix.md:11
- This role-based selector rule conflicts with the companion spec's rule that application code never branches on roles and checks capabilities. The distinction affects real grants:
meeting_coordinatoris an explicit Project role in the live model but grantsviewer, notauditor, so “auditor or explicit role” leaves its context-entry behavior undefined. Use a named context-entry capability (possibly inherited through qualifying roles) rather than an unspecified role alternative.
Context selector eligibility -> auditor or explicit role grant
docs/architecture/frontend/permission-persona-navigation-model-preread.md:236
- “Not yet started” is a mutable ticket status that will silently stale in an architecture document. The repository documentation checklist (
docs/reviews/docs-checklist.md:33-49) says to replace status tracking with a concise statement of what is implemented and link the outstanding work item; keep the design decision and ticket reference without recording workflow state.
This issue also appears on line 238 of the same file.
- **Health Metrics** stays ED-gated by design — this page does not migrate to a shared capability (LFXV2-2726 is evaluating an LF Staff answer, not yet started).
docs/architecture/frontend/permission-persona-navigation-model-preread.md:480
- The live
b2b_org.auditorrelation already accepts[team#member]; the schema itself does not identify an LF Staff team. Project's “global LF Staff Team” entry inPERMISSIONS.mdis preserved external inheritance/provisioning metadata, not an expression inmodel.fga. Therefore a model-only change cannot grant org access: this ask must specify how the LF Staff team tuple is provisioned for every existing and newly created B2B organization (or define a new global relation together with that provisioning), otherwise the requested inheritance remains ineffective.
2. **Org lens for LF staff.** LF staff should get org-lens switching the same
way they get project/foundation access today — through team inheritance,
not impersonation. `PERMISSIONS.md` shows Project's Auditor relation
already inherits from the global LF Staff Team; the B2B Organization
section does not have the equivalent inheritance. This needs an LF Staff
Team → B2B Organization auditor inheritance added to the model — a model
change, not a UI workaround.
Eric reviewed the PR directly (15 inline comments) with a much more
precise, authoritative correction of how OpenFGA actually works than
either bot review captured:
- Core Principle was flatly wrong about the model: roles are not
"bundles of permissions" and permissions are not "assigned to
roles." Rewrote per his explanation - relations form a graph
evaluated transitively across objects, tuples are the concrete data
edges, and permissions are RuleSets gating API routes, not labels
attached to a relation. Fixed the "role" -> "relation" mislabeling
throughout (OpenFGA has no "role" concept).
- Fixed the "code never branches on role or persona" claim - code
correctly branches on evaluated relation checks; it must never
branch on persona labels for access decisions. Reworded the key
rule and the paragraph Eric flagged as self-contradictory.
- TL;DR: "auditor is the only relation that matters for context
entry" replaces the vaguer "auditor or explicit role grant," per his
point that any higher relation includes auditor by inheritance.
"What can I do" no longer flattens to "writer permission" - stated
as the action-specific relation its API call requires (organizer,
poll author, etc. are not writer).
- Viewer/Auditor definitions tightened to his exact phrasing
(privileged data + subordinate/connected objects, not "inside").
- "Current UI Facts": corrected "grants write access unconditionally"
- the guard only skips its own client-side check and lets the route
render; it cannot grant an actual write, which is enforced
downstream. Tied the open question (dead-end vs. real gap) to the
existing P0 verification ask.
- Model Asks #1 resolved, not left open: per Eric, executive_director
stays as an FGA relation. Model Asks #2 now points to a filed ticket
(LFXV2-2936) instead of a dangling "ask," per his push to not leave
open questions unresolved in an architecture doc.
- LF Staff Mode reframed as an explicitly open product question in
both docs - Eric's challenge (staff already get broad auditor via
team inheritance; what would "mode" add beyond that?) has no answer
in this document, so stop asserting it as a settled requirement.
- Renamed "Meeting Ask" -> "Contract Summary": referencing an
undefined meeting was out of place; PR review is the actual
agreement mechanism.
LFXV2-2913
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
CodeRabbit ran the repo's actual guard code and cross-referenced the existing persona-content-matrix.md (a code-verified reference doc neither prior pass had linked to): - Existing Item Action From Me: fixed imprecise wording that implied meeting_coordinator applies to committee/group targets - it's scoped to meeting actions only; committee.writer covers committee/group targets across meetings/surveys/votes. - Meetings feature decision: this doc states the target model, but writer.guard.ts on main still has an unconditional ED-persona fast path ahead of the organizer-grant check. Said so explicitly and cross-linked persona-content-matrix.md's Meetings write paths table instead of letting the two docs silently disagree. - Cross-linked persona-content-matrix.md from both docs' intros (the code-verified current-state reference the "align the persona content matrix" follow-up was gesturing at) and updated that follow-up to reflect that the matrix already exists. - Replaced the vague "verify with the platform team" P0 ask with a reference to the ticket that already covers it - LFXV2-1662, "Review backend write enforcement per managed domain" - found via persona-content-matrix.md's own cross-reference. LFXV2-2913 Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (18)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:91
- “Explicit role” is broader than
auditor: the live model makes Project Meeting Coordinator directly assignable, but it inheritsviewer, notauditor. The later selector/defaulting rules therefore admit meeting coordinators even though lines 9 and 75–78 say evaluated auditor is the sole context-entry relation. Useauditorconsistently, or explicitly enumerate any non-auditor roles that should enter a context.
Terminology pass applied throughout this document: everywhere a gate on
selector eligibility or context entry previously said "view permission," it
now reads "auditor or explicit role"; everywhere the meaning was
discoverability only, it reads "viewer/discoverable."
docs/architecture/frontend/permission-persona-decision-matrix.md:93
- Meeting Coordinator is a Project relation; it does not apply when the resolved target is a committee/group.
writerGuardchecksproject.meetingCoordinatorfor project-targeted meetings and checkscommittee.writerfor committee/group targets. The current wording attaches both alternatives to the committee/group branch and then incorrectly falls back to writer-only behavior on the next lines.
- **Required permission:** Viewer/discoverable eligibility or item eligibility for read actions. The action-specific grant on the item's resolved target object for write actions: writer permission for Foundation/Project targets; `committee.writer` for committee/group targets; and `project.meeting_coordinator` only for meeting actions.
- **Destination:** Stay in Me or open the item detail/drawer with target context attached.
- **Allowed actions:** Read actions follow item eligibility. Create/manage actions are visible or enabled when writer permission passes.
- **Denied actions:** If writer permission fails, keep eligible view/read actions only.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:246
- This is not the current
writerGuardcontract: after the ED shortcut it checksproject.writer, Project Meeting Coordinator for meetings, and Committee Writer for meetings/surveys/votes; it does not call a singlecanWrite(). The target should remove only the ED shortcut while preserving those action-specific paths, otherwise this spec appears to regress the shipped committee/meeting-coordinator support described at line 165.
Current writerGuard = Executive Director fast path or canWrite()
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-navigation-model-preread.md:475
- This also contradicts the Writer Actions decision at line 257, which says retaining, renaming, or removing
executive_directorremains the platform team's call. Here the same spec marks “keep” as resolved. Choose one status so the target model does not simultaneously leave and settle the platform decision.
1. **Permission bundling for ED-derived capabilities — resolved: keep
`executive_director` as an FGA relation.** The app checks `auditor`,
`writer`, `marketing_auditor`, and `campaign_manager` directly and never
branches on the `executive_director` relation itself (see Writer Actions
above). Per Eric Searcy's review, the relation stays in the model rather
docs/architecture/frontend/permission-persona-decision-matrix.md:56
- This still restricts Me create/manage to a Foundation/Project writer, contradicting the supported committee/group targets documented at line 98 and shipped in PR #1193. Committee writers must be able to start meeting/survey/vote flows from Me, and Project Meeting Coordinators can start meetings without project writer.
- **Create/manage rule:** Allowed only after the action resolves or asks for a target Foundation/Project context and writer permission passes.
docs/architecture/frontend/permission-persona-decision-matrix.md:361
- Direct write URLs have the same non-writer authorization paths as picker navigation: committee-targeted meeting/survey/vote routes use Committee Writer, and project meeting routes accept Project Meeting Coordinator. Requiring
writerhere contradicts the matrix's own feature decisions and would specify a fail-closed redirect for valid deep links.
- **Required permission:** Resolved target context plus writer permission.
- **Destination:** Requested route only if writer check passes.
- **Allowed actions:** Continue if authorized.
- **Denied actions:** Redirect or fail closed if target context is missing or writer permission fails.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:409
- These Me acceptance cases reintroduce the writer-only restriction that the Me Lens rules above removed. A committee writer or Project Meeting Coordinator can legitimately complete the supported target-specific flow without project writer, so acceptance must test the action-specific relation instead.
Selected Foundation/Project context + no writer permission = read-only context experience
Me-originated task + target context + writer permission = allowed action
docs/architecture/frontend/permission-persona-decision-matrix.md:109
- Pending shared-resource actions are not uniformly project-writer operations. Agenda/meeting management uses the meeting Organizer relation, while personal responses use their owner/participant relation. Requiring writer for every modification repeats the same false restriction this matrix avoids in its top-level decision rule.
- **Required permission:** Viewer/discoverable eligibility for the pending item. Writer permission only for actions that modify the target context.
- **Destination:** Pending action detail or target context.
- **Allowed actions:** View/complete personal response actions when eligible. Manage shared resources only with writer permission.
- **Denied actions:** Do not expose target-context management controls when writer permission is absent.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:400
- This work plan would audit all affordances and Me actions against contextual writer, even though meetings and committee-targeted flows intentionally use other relations. That would direct the implementation to remove valid Meeting Coordinator/Committee Writer paths. Inventory each affordance against its API-required relation instead.
- Inventory every create/manage affordance in Foundation/Project pages.
- Confirm each affordance is gated by contextual writer permission.
- Confirm direct create/edit/admin routes are guarded.
- Confirm backend/downstream writes remain authoritative.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:239
- The action list immediately above includes meetings, votes, and surveys, but this rule says absence of project writer makes the whole context read-only. That contradicts the documented Project Meeting Coordinator and Committee Writer paths. Gate each affordance by its action-specific relation; do not make project writer a universal switch.
Selected Foundation/Project context + writer permission = create/manage affordances
No writer permission = read-only context experience
docs/architecture/frontend/permission-persona-navigation-model-preread.md:9
- This extends the auditor-only entry contract to Organization, but the companion matrix never defines Org entry and the current
AccountContextService.hasOrgSelectorAccessalso admits persona-seededavailableAccounts()with no writer/auditor grant. Either scope this statement to Foundation/Project or document the intended Org migration; otherwise it silently invalidates the existing Board Member Org path without any corresponding decision or work item.
This issue also appears on line 88 of the same file.
- **Where can I go?** Outside of Me, `auditor` access (explicit or inherited) is what's needed to browse into a Foundation/Project/Organization context. It's the only relation that matters for context entry: any higher relation (writer, owner) includes `auditor` by inheritance.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:500
- The summary reverts to writer-only authorization even though this document's TL;DR and Me rules correctly require the action-specific relation. Project meeting coordinators, committee writers, direct meeting organizers, and response owners can perform supported writes without project
writer; this summary would make the agreed contract reject them.
Sidebar/page/content visibility -> persona (presentation only)
Action authority -> existing contextual writer permission
Campaigns/Marketing Impact -> named capability (campaign_manager/marketing_auditor), not ED persona
Health Metrics -> stays ED-gated by design, pending an LF Staff answer (LFXV2-2726)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:475
- The PR summary says this Model Ask is for ED relation removal, while the document now records the opposite decision: keep
executive_director. Update the PR description or this section so approval is not presented as agreement to two contradictory platform asks.
This issue also appears on line 470 of the same file.
1. **Permission bundling for ED-derived capabilities — resolved: keep
`executive_director` as an FGA relation.** The app checks `auditor`,
`writer`, `marketing_auditor`, and `campaign_manager` directly and never
branches on the `executive_director` relation itself (see Writer Actions
above). Per Eric Searcy's review, the relation stays in the model rather
docs/architecture/frontend/permission-persona-navigation-model-preread.md:124
writerGuardis not attached to any Documents route:DOCUMENT_ROUTEScontains only the dashboard guarded byauthGuard, and the changed route inventory has no document create/edit route. This current-state paragraph therefore incorrectly attributes the ED fast path to document routes. Remove Documents from this list or name the actual guarded route if one exists.
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main`: both skip their own permission check for ED persona and let the route open — for meetings, votes, surveys, mailing lists, newsletters, and document create/edit routes. That does not mean the write itself is granted; the UI is subordinate to the API's enforcement, and an ED cannot get project `writer` access just because a guard let the route render. It is very likely a guard bug (a misleading UI-only affordance that a downstream write would then reject) rather than a permission the model grants: `executive_director` does not inherit project `writer`, so none of those general write actions are backed by any ED-inherited relation. Whether this is purely a confusing dead-end (guard says yes, API says no) or an actual gap depends on whether the downstream API independently enforces `writer` for these routes — see the P0 verification ask below. The model does route two _intentional_ marketing permissions through `executive_director` — `marketing_auditor` (read) and `campaign_manager` (write, scoped to Campaigns) — which `PERMISSIONS.md`'s rendered Project table omits entirely, so it looks like ED grants nothing but reads even though the live model (`model.fga`) says otherwise. See Writer Actions and Model Asks below for how the app should check these.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:74
vieweris not uniformly “discoverability only” in the live model. Scheduled Meeting viewer access includes registrants/RSVPs, and Committee viewer access includes members, invites, and applications; those viewer relations can come from participant/member grants as well as public flags. Scope this definition to Project/Foundation context discovery instead of teaching that viewer never exposes connected participant data, or implementers may choose the wrong read relation for other object types.
- **Viewer** — discoverability only. You can tell the thing exists and see
limited (typically public) data about it, but not privileged data or its
subordinate/connected objects (participants, formation-stage child
projects, private documents). Viewer is not ordinarily assigned directly:
it is conditional on object attributes (public/conditional) or inherited
from another relation you hold (a committee `member` relation always
inherits `viewer`, too). Maps to Discovery.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:178
- Vote/survey results do not follow the ordinary
viewerrelation. The model defines a separateresults_viewerrelation, and participant result access is conditionally enabled, so a user can view the item but still be denied results. Keep details and result eligibility separate here.
- **Vote or survey:** open the item; view/results follow viewer/discoverable eligibility for that item, edit/close follows writer permission.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:177
- Existing meeting management is gated by the meeting's
organizerrelation, not only by projectwriter. The model also grants organizer through Project Meeting Coordinator, Committee Writer, and direct organizer tuples, so this example incorrectly classifies those authorized users as read-only.
This issue also appears in the following locations of the same file:
- line 238
- line 245
- line 396
- line 408
- **Meeting card:** open the meeting with its context; edit/manage only if writer permission applies.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:300
- Group/working-group authorization is already modeled as
committee.writerand is already used by the shipped meeting/survey/vote flows described at line 165. Saying the permission still needs to be modeled contradicts the current model and this document's own status. If the remaining gap is coverage for additional group actions, name that gap instead.
- Model group-scoped and working-group-scoped writer permission this cycle.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (17)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:124
- This current-state inventory incorrectly includes document create/edit routes:
DOCUMENT_ROUTESexposes only the dashboard and neitherwriterGuardnornewsletterAccessGuardprotects it. Conversely, committee create/edit routes do usewriterGuard. Correcting the domain list is important because this paragraph drives the later guard-removal inventory.
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main`: both skip their own permission check for ED persona and let the route open — for meetings, votes, surveys, mailing lists, newsletters, and document create/edit routes. That does not mean the write itself is granted; the UI is subordinate to the API's enforcement, and an ED cannot get project `writer` access just because a guard let the route render. It is very likely a guard bug (a misleading UI-only affordance that a downstream write would then reject) rather than a permission the model grants: `executive_director` does not inherit project `writer`, so none of those general write actions are backed by any ED-inherited relation. Whether this is purely a confusing dead-end (guard says yes, API says no) or an actual gap depends on whether the downstream API independently enforces `writer` for these routes — see the P0 verification ask below. The model does route two _intentional_ marketing permissions through `executive_director` — `marketing_auditor` (read) and `campaign_manager` (write, scoped to Campaigns) — which `PERMISSIONS.md`'s rendered Project table omits entirely, so it looks like ED grants nothing but reads even though the live model (`model.fga`) says otherwise. See Writer Actions and Model Asks below for how the app should check these.
docs/architecture/frontend/permission-persona-decision-matrix.md:93
- After line 90 correctly defines action-specific grants, these outcomes again treat project writer as the only write authority. That misclassifies committee writers, meeting coordinators, and organizers; keep the outcome phrased in terms of the required relation.
- **Allowed actions:** Read actions follow item eligibility. Create/manage actions are visible or enabled when writer permission passes.
- **Denied actions:** If writer permission fails, keep eligible view/read actions only.
docs/architecture/frontend/permission-persona-decision-matrix.md:109
- Pending actions are not uniformly controlled by contextual writer: the document's core principle already cites author-only response edits, and meeting management uses resource-specific organizer authority. Requiring writer for every modification would hide valid personal/resource actions.
- **Required permission:** Viewer/discoverable eligibility for the pending item. Writer permission only for actions that modify the target context.
- **Destination:** Pending action detail or target context.
- **Allowed actions:** View/complete personal response actions when eligible. Manage shared resources only with writer permission.
- **Denied actions:** Do not expose target-context management controls when writer permission is absent.
docs/architecture/frontend/permission-persona-decision-matrix.md:361
- Direct routes use the same action-specific authorization as other entry points; they are not uniformly project-writer-only. Current meeting routes admit meeting coordinators or committee writers for creation, and existing-resource edits may require a resource relation such as meeting
organizer. This edge-case contract would incorrectly fail those valid deep links.
- **Required permission:** Resolved target context plus writer permission.
- **Destination:** Requested route only if writer check passes.
- **Allowed actions:** Continue if authorized.
- **Denied actions:** Redirect or fail closed if target context is missing or writer permission fails.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:181
- These examples revert to project
writereven though the rule immediately above is target object plus action-specific relation. In particular, managing an existing meeting is authorized by the meeting'sorganizerrelation, while committee-scoped meeting/vote/survey flows can usecommittee.writer; readers implementing from these examples would reject valid users.
- **Pending agenda action:** resolve the target group/project/foundation; allow agenda management only if writer permission applies.
- **Meeting card:** open the meeting with its context; edit/manage only if writer permission applies.
- **Vote or survey:** open the item; view/results follow viewer/discoverable eligibility for that item, edit/close follows writer permission.
- **Document row:** open the document context; upload/folder/link actions follow writer permission.
- **Newsletter draft:** open the draft with its target audience context; edit/delete/send follows writer permission for that context.
- **Newsletter create:** ask for the target Foundation/Project and audience first; then apply writer permission.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:253
- This leaves Health Metrics persona-gated while the surrounding target contract says ED-shaped pages must use named permissions and never a persona guard. The next paragraph confirms the current Health Metrics guard is the pure
executiveDirectorGuard, and this bullet names no capability to replace it, so the target state has an unresolved authorization exception. Either define its permission gate or explicitly revise the core “persona never access” contract.
- **Health Metrics** stays ED-gated by design — this page does not migrate to a shared capability (LFXV2-2726 is evaluating an LF Staff answer, not yet started).
docs/architecture/frontend/permission-persona-navigation-model-preread.md:475
- This says the platform decision is resolved in favor of retaining
executive_director, but line 257 says whether that relation stays, is renamed, or is bundled differently remains the platform team's call. The PR description also presents relation removal as a model ask. These are mutually exclusive statuses; update the document and PR summary to the actual decision.
1. **Permission bundling for ED-derived capabilities — resolved: keep
`executive_director` as an FGA relation.** The app checks `auditor`,
`writer`, `marketing_auditor`, and `campaign_manager` directly and never
branches on the `executive_director` relation itself (see Writer Actions
above). Per Eric Searcy's review, the relation stays in the model rather
docs/architecture/frontend/permission-persona-navigation-model-preread.md:501
- The summary collapses all action authority back to contextual writer checks, contradicting the document's own core rule and supported committee-writer, meeting-coordinator, and meeting-organizer paths. Because this block is the proposed contract, it should preserve “resolved target object + action-specific relation.”
Action authority -> existing contextual writer permission
Campaigns/Marketing Impact -> named capability (campaign_manager/marketing_auditor), not ED persona
Health Metrics -> stays ED-gated by design, pending an LF Staff answer (LFXV2-2726)
Me-originated actions -> carry target context before writer checks
docs/architecture/frontend/permission-persona-decision-matrix.md:45
- This P0 gate contradicts the matrix's governing rule on line 14 by requiring
writerfor every write. Supported writes also usecommittee.writer,project.meeting_coordinator, and resource-specific relations such as meetingorganizer; making this the generic gate would deny valid create/manage paths.
- **Required permission:** Resolved target context plus server-enforced writer permission.
- **Destination:** Write flow only after UI and API permission checks agree.
- **Allowed actions:** Continue when contextual writer permission passes.
- **Denied actions:** Fail closed if the target context is missing, stale, no-grant, or not writer-permitted.
docs/architecture/frontend/permission-persona-decision-matrix.md:56
- This excludes the shipped committee/group targets and meeting-coordinator path described later on line 98. Me create/manage actions must resolve any supported target object and check its action-specific relation, not require a Foundation/Project writer in every case.
- **Create/manage rule:** Allowed only after the action resolves or asks for a target Foundation/Project context and writer permission passes.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:246
- This guard summary is already false for the current implementation and would regress the target:
writerGuardalso acceptsproject.meetingCoordinatorandcommittee.writer, and the proposed model repeatedly says to preserve action-specific relations. Removing only the ED fast path must not collapse those supported paths tocanWrite().
Current writerGuard = Executive Director fast path or canWrite()
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-navigation-model-preread.md:410
- These Me acceptance cases again require contextual writer, excluding the committee-writer and meeting-coordinator paths documented earlier. Since acceptance criteria are likely to become implementation tests, retain the target-object/action-specific-relation contract here.
Me-originated task + target context + writer permission = allowed action
Me create action + selected target context + writer permission = allowed action
docs/architecture/frontend/permission-persona-navigation-model-preread.md:419
- A direct edit without project writer is not necessarily unauthorized: existing meeting updates can be authorized by the meeting's
organizerrelation, and committee-scoped routes have their own relation paths. Phrase this regression around failure of the action-specific relation rather than writer alone.
- Direct edit route without writer permission fails closed or redirects.
docs/architecture/frontend/permission-persona-decision-matrix.md:90
- This is the “Existing Item” case, but its write list contains only creation/context grants and omits resource-level authority. The current meeting path, for example, requires
organizeron the existing meeting for update/delete/registrant operations. Define existing-item writes by their resource/action-specific relation rather than this incomplete grant list.
- **Required permission:** Viewer/discoverable eligibility or item eligibility for read actions. The action-specific grant on the item's resolved target object for write actions: writer permission for Foundation/Project targets; `committee.writer` for committee/group targets; and `project.meeting_coordinator` only for meeting actions.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:401
- This work item narrows Me-originated actions to writer checks, although the same section's accepted model includes committee writer, meeting coordinator, and resource-specific relations. Make the implementation task resolve the action-specific relation so it does not undo the corrected Me contract.
- Confirm Me-originated actions resolve target context before applying writer checks.
docs/architecture/frontend/permission-persona-decision-matrix.md:209
- This combines creation and management under project/committee-level creator relations, but the current write-path documentation states that update/delete/registrant operations require
organizeron the existing meeting. Without that distinction, the target matrix incorrectly grants or denies existing-meeting management based on the creation relation.
- **Create/manage:** Requires the organizer-granting relation for the target — Project/Foundation Writer, Project Meeting Coordinator (meetings only), or Committee Writer when the target is a committee/group — per `PERMISSIONS.md`'s Scheduled Meeting inheritance (`Organizer` inherits from Project Meeting Coordinator, Committee Writer, Project Writer). This is the target state; `writerGuard` on `main` still has an unconditional ED-persona fast path ahead of this check (documented in [`persona-content-matrix.md`](./persona-content-matrix.md#meetings-write-paths), tracked for removal per Current UI Facts in the preread).
docs/architecture/frontend/permission-persona-navigation-model-preread.md:123
- PR #1193 already shipped composed BFF endpoints at
/api/create-picker/{tree,tree/children,search}that answer what the user can create and where, including committee targets. If this means there is no replacement upstream platform API, say that explicitly; as written, “no committed replacement” contradicts the shipped implementation cited on the preceding line.
This issue also appears in the following locations of the same file:
- line 124
- line 176
- line 245
- line 253
- line 401
- ...and 4 more
- A backend "what can I create, and where" API covering group/committee targets (LFXV2-2753) was rescoped after #1130 shipped and its ticket status is now Discarded — it is not in progress. There is no committed replacement work item for that API today.
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (12)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:177
- This reverts to a blanket writer check even though the target model above explicitly names meeting
organizeras an action-specific authority, and the code-verified matrix documents update/delete as guarded byorganizeron the meeting. A meeting organizer must not be described as unable to manage the meeting merely because they lack current project writer access.
- **Meeting card:** open the meeting with its context; edit/manage only if writer permission applies.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:410
- This acceptance block again makes project/foundation
writerthe universal action gate, so it excludes the already-supported committee-writer and meeting-coordinator paths described at line 165 and in the companion matrix. P3 should consistently evaluate the API-required relation on the resolved target; the same blanket wording also appears in the “Confirm each affordance” bullet above.
Selected Foundation/Project context + writer permission = create/manage affordance visible/enabled
Selected Foundation/Project context + no writer permission = read-only context experience
Me-originated task + target context + writer permission = allowed action
Me create action + selected target context + writer permission = allowed action
docs/architecture/frontend/permission-persona-navigation-model-preread.md:124
- This inventory also omits Group/Committee create and edit routes:
committees.routes.tsapplieswriterGuardto both withwriteFeature: 'committees', so ED persona currently bypasses their project-writer check too. Include that domain so the proposed fast-path removal and regression inventory cover every affected route.
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main`: both skip their own permission check for ED persona and let the route open — for meetings, votes, surveys, mailing lists, newsletters, and document create/edit routes. That does not mean the write itself is granted; the UI is subordinate to the API's enforcement, and an ED cannot get project `writer` access just because a guard let the route render. It is very likely a guard bug (a misleading UI-only affordance that a downstream write would then reject) rather than a permission the model grants: `executive_director` does not inherit project `writer`, so none of those general write actions are backed by any ED-inherited relation. Whether this is purely a confusing dead-end (guard says yes, API says no) or an actual gap depends on whether the downstream API independently enforces `writer` for these routes — see the P0 verification ask below. The model does route two _intentional_ marketing permissions through `executive_director` — `marketing_auditor` (read) and `campaign_manager` (write, scoped to Campaigns) — which `PERMISSIONS.md`'s rendered Project table omits entirely, so it looks like ED grants nothing but reads even though the live model (`model.fga`) says otherwise. See Writer Actions and Model Asks below for how the app should check these.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:246
- This summary drops the existing meeting-coordinator and committee-writer branches from both the current and target guard. The intended change is to remove only the ED-persona shortcut while retaining every action-specific relation check; otherwise implementers could regress the supported committee meeting/survey/vote and meeting-coordinator flows documented above.
Current writerGuard = Executive Director fast path or canWrite()
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-navigation-model-preread.md:239
- This rule still treats project/foundation
writeras the only source of every listed affordance, despite the meeting-coordinator and committee-writer exceptions established earlier. Permission absence is also per action: a non-writer meeting coordinator can have a read-only project generally while still receiving the meeting affordance.
Selected Foundation/Project context + writer permission = create/manage affordances
No writer permission = read-only context experience
docs/architecture/frontend/permission-persona-decision-matrix.md:81
- Explicit context selection should not turn the action model back into a universal writer check. A selected context can legitimately expose a meeting action through
meeting_coordinatoror a committee-scoped action throughcommittee.writer; keep the permission decision action-specific.
- **Allowed actions:** Explicit selection wins over defaulting. Create/manage follows writer permission for the selected context.
docs/architecture/frontend/permission-persona-decision-matrix.md:73
- This would hide all create/manage actions from a project meeting coordinator who lacks project writer, even though the Meetings decision below authorizes that relation. Apply the action-specific relation rule instead of collapsing Project context to writer-only.
- **Allowed actions:** Read context data. Create/manage only if writer permission exists for the selected project.
docs/architecture/frontend/permission-persona-decision-matrix.md:116
- This framing omits non-writer action relations, and the “without writer” scenarios below consequently deny all create/manage work even when the user could hold
meeting_coordinatororcommittee.writer. Writer presence alone cannot classify the whole presentation as writable/read-only; either scope each denial to writer-backed resources or state that no applicable action-specific grant exists.
Persona changes what the experience looks like (layout, emphasis, copy,
ordering). It never decides whether the user can enter the context, read its
data, or write to it — those outcomes are stated below purely in permission
terms (auditor grant, writer grant, named capability).
docs/architecture/frontend/permission-persona-navigation-model-preread.md:257
- This still presents retention or removal of
executive_directoras an open platform decision, but Model Ask 1 now says the decision is resolved and the relation will remain. Leaving both positions in the target spec makes the platform contract ambiguous; update this paragraph to reflect the resolved decision.
Whether the `executive_director` relation itself stays in the model, is renamed, or is bundled differently is the platform team's call, not the app's (see Model Asks below) — the app checks `marketing_auditor` and `campaign_manager` directly and does not care which relations feed them. Create/edit/manage routes should not use ED as an authorization shortcut unless the user also has writer permission for the selected target context.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:124
- The document write paths are not covered by either guard named here.
documents.routes.tsprotects only the dashboard withauthGuard, andDocumentsDashboardComponent.canUploadchecks only that a project/foundation context is active, so Upload File/New Folder/Add Link are currently shown without a writer check. Classifying Documents as another ED-fast-path case hides a distinct current-state gap that the P0 verification should inventory separately.
This issue also appears in the following locations of the same file:
- line 124
- line 177
- line 238
- line 245
- line 407
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main`: both skip their own permission check for ED persona and let the route open — for meetings, votes, surveys, mailing lists, newsletters, and document create/edit routes. That does not mean the write itself is granted; the UI is subordinate to the API's enforcement, and an ED cannot get project `writer` access just because a guard let the route render. It is very likely a guard bug (a misleading UI-only affordance that a downstream write would then reject) rather than a permission the model grants: `executive_director` does not inherit project `writer`, so none of those general write actions are backed by any ED-inherited relation. Whether this is purely a confusing dead-end (guard says yes, API says no) or an actual gap depends on whether the downstream API independently enforces `writer` for these routes — see the P0 verification ask below. The model does route two _intentional_ marketing permissions through `executive_director` — `marketing_auditor` (read) and `campaign_manager` (write, scoped to Campaigns) — which `PERMISSIONS.md`'s rendered Project table omits entirely, so it looks like ED grants nothing but reads even though the live model (`model.fga`) says otherwise. See Writer Actions and Model Asks below for how the app should check these.
docs/architecture/frontend/permission-persona-decision-matrix.md:134
- This scenario incorrectly makes an ED without project writer entirely read-only, even though the preread establishes that
campaign_manageris a write-capable named capability inherited byexecutive_director. The matrix should preserve Campaigns writes when that capability passes while denying unrelated project writes.
- **Allowed actions:** Read ED-shaped pages only where the named capability
behind them (see Model Asks in the preread) is granted — not because the ED
persona is detected.
- **Denied actions:** Create/edit/manage routes and affordances.
docs/architecture/frontend/permission-persona-decision-matrix.md:64
- The Foundation default case falls back to blanket project writer authorization, contradicting the matrix's P0 rule and its supported meeting-coordinator/committee-writer paths. Context entry still requires auditor access, but each affordance must use its own API-required relation.
This issue also appears in the following locations of the same file:
- line 73
- line 81
- line 113
- **Allowed actions:** Read context data. Create/manage only if writer permission exists for the selected foundation.
Embed permission-model.svg in the preread (right after Core Principle) and point to it from the decision matrix. Two labels in the diagram have drifted from the current doc text - flagging rather than silently shipping the mismatch: - Diagram subtitle: "Roles are bundles of permissions in OpenFGA." Eric Searcy's review corrected this exact claim in the Core Principle text (relations are a transitively-evaluated graph; permissions are RuleSets on API routes, not labels attached to a relation) - the diagram was drawn before that correction landed. - Diagram footer: "Keep, rename, or remove any bundle (ED relation, teams) - the platform team's call," presenting the ED-relation question as still fully open. Model Asks #1 now states this is resolved: per Eric's review, executive_director stays as an FGA relation. Everything else checked clean against the final doc text: the four product gates (viewer / auditor-or-explicit-role / campaign_manager + marketing_auditor / action-specific relation on resolved target), persona-as-presentation-only, and the bundling examples (LF Staff Team -> auditor, executive_director -> marketing_auditor + campaign_manager, committee member -> viewer, project writer -> committee.writer) all match model.fga and the current doc revisions. LFXV2-2913 Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (8)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:93
- “Explicit role grant” is broader than
auditor: a direct projectmeeting_coordinatortuple is an explicit user/object grant, but the live model includes it inviewer, notauditor. This wording would therefore make a grant that this spec intentionally supports only from Me eligible for Foundation/Project context entry, contradicting lines 77–80 and 167. Use the evaluatedauditorrelation for selector/context eligibility; qualifying writer/owner/ED grants already inherit it.
Terminology pass applied throughout this document: everywhere a gate on
selector eligibility or context entry previously said "view permission," it
now reads "auditor or explicit role"; everywhere the meaning was
discoverability only, it reads "viewer/discoverable."
docs/architecture/frontend/permission-persona-navigation-model-preread.md:503
- The contract summary falls back to blanket contextual
writerchecks even though this spec now preserves action-specific paths such as committee writer, meeting coordinator, and response owner. Those users may legitimately lack project writer, so implementers following the summary would regress supported actions. Keep the condensed contract aligned with the target-object + API-required relation rule.
Action authority -> existing contextual writer permission
Campaigns/Marketing Impact -> named capability (campaign_manager/marketing_auditor), not ED persona
Health Metrics -> stays ED-gated by design, pending an LF Staff answer (LFXV2-2726)
Me-originated actions -> carry target context before writer checks
docs/architecture/frontend/permission-persona-navigation-model-preread.md:259
- This paragraph still says the ED relation may be removed or renamed, but Model Ask 1 below now records the resolved decision to keep
executive_director. Reconcile this target-state paragraph with that decision; otherwise the same spec gives platform implementers opposite requirements.
Whether the `executive_director` relation itself stays in the model, is renamed, or is bundled differently is the platform team's call, not the app's (see Model Asks below) — the app checks `marketing_auditor` and `campaign_manager` directly and does not care which relations feed them. Create/edit/manage routes should not use ED as an authorization shortcut unless the user also has writer permission for the selected target context.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:412
- These Me-originated acceptance cases still require blanket writer permission, contradicting the action-specific contract added earlier. Committee writers and meeting coordinators can perform supported creates without project writer, and response owners can perform personal actions without any writer relation. Acceptance should validate the API-required relation on the resolved target instead.
Me-originated task + target context + writer permission = allowed action
Me create action + selected target context + writer permission = allowed action
docs/architecture/frontend/permission-persona-decision-matrix.md:14
- This alternative admits more than the target
auditorrelation. For example,project#meeting_coordinatoris an explicit role tuple but does not inheritauditorin the live model; the preread explicitly says such a user may act from Me without project-level auditor access. Making every explicit role selector-eligible contradicts that flow. Define context entry solely by the evaluatedauditorrelation.
Authoritative role/permission model -> selector eligibility and defaulting
Context selector eligibility -> auditor or explicit role grant
Data/page visibility -> permission (auditor/explicit role or named capability)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:478
- The PR summary says this Model Ask concerns removing the ED relation, but the updated section now records the opposite decision: keep
executive_director. Update the PR description so reviewers and future readers are not given a stale statement of the change’s purpose.
1. **Permission bundling for ED-derived capabilities — resolved: keep
`executive_director` as an FGA relation.** The app checks `auditor`,
`writer`, `marketing_auditor`, and `campaign_manager` directly and never
branches on the `executive_director` relation itself (see Writer Actions
above). Per Eric Searcy's review, the relation stays in the model rather
than being removed or replaced — it remains the bundle that carries
docs/architecture/frontend/permission-persona-navigation-model-preread.md:126
- The current-state route inventory is inaccurate:
writerGuardprotects meetings, committees, mailing lists, surveys, and votes, whilenewsletterAccessGuardprotects newsletters; Documents has only an authenticated dashboard route and its write controls are inline rather than create/edit routes. Replace Documents with Committees here so this fact-check section matches the route tables.
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main`: both skip their own permission check for ED persona and let the route open — for meetings, votes, surveys, mailing lists, newsletters, and document create/edit routes. That does not mean the write itself is granted; the UI is subordinate to the API's enforcement, and an ED cannot get project `writer` access just because a guard let the route render. It is very likely a guard bug (a misleading UI-only affordance that a downstream write would then reject) rather than a permission the model grants: `executive_director` does not inherit project `writer`, so none of those general write actions are backed by any ED-inherited relation. Whether this is purely a confusing dead-end (guard says yes, API says no) or an actual gap depends on whether the downstream API independently enforces `writer` for these routes — see the P0 verification ask below. The model does route two _intentional_ marketing permissions through `executive_director` — `marketing_auditor` (read) and `campaign_manager` (write, scoped to Campaigns) — which `PERMISSIONS.md`'s rendered Project table omits entirely, so it looks like ED grants nothing but reads even though the live model (`model.fga`) says otherwise. See Writer Actions and Model Asks below for how the app should check these.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:62
- The image alternative text repeats both stale abstractions that the accompanying prose rejects: relations/roles are not permission bundles, and the access check evaluates a relation rather than an API action. Correct the alt text as well as the visible SVG so screen-reader and image-fallback users receive the same model.
This issue also appears in the following locations of the same file:
- line 90
- line 259
- line 411
- line 500

Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (5)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:126
- This current-state inventory incorrectly includes document create/edit routes under the ED fast paths.
documents.routes.tsdefines only the dashboard route withauthGuard; document writes are in-page controls, whilewriterGuardactually protects committee create/edit routes (as the linkedpersona-content-matrix.mdalso records). Keeping this list as written sends the P3 guard audit toward a nonexistent document route and omits a real guarded domain.
- The Executive Director fast path is still present in `writerGuard` (`writer.guard.ts`) and in `newsletter-access.guard.ts` on `main`: both skip their own permission check for ED persona and let the route open — for meetings, votes, surveys, mailing lists, newsletters, and document create/edit routes. That does not mean the write itself is granted; the UI is subordinate to the API's enforcement, and an ED cannot get project `writer` access just because a guard let the route render. It is very likely a guard bug (a misleading UI-only affordance that a downstream write would then reject) rather than a permission the model grants: `executive_director` does not inherit project `writer`, so none of those general write actions are backed by any ED-inherited relation. Whether this is purely a confusing dead-end (guard says yes, API says no) or an actual gap depends on whether the downstream API independently enforces `writer` for these routes — see the P0 verification ask below. The model does route two _intentional_ marketing permissions through `executive_director` — `marketing_auditor` (read) and `campaign_manager` (write, scoped to Campaigns) — which `PERMISSIONS.md`'s rendered Project table omits entirely, so it looks like ED grants nothing but reads even though the live model (`model.fga`) says otherwise. See Writer Actions and Model Asks below for how the app should check these.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:255
- This exception contradicts the target contract stated throughout these artifacts: lines 18–20 say every access gate is an evaluated relation check, the companion matrix says persona never decides whether data can be read, and the diagram says persona “never gates access.” An ED persona guard for Health Metrics is still an access decision. Either assign this page a named capability like the other pages, or explicitly revise the core contract, matrix, and diagram to document a deliberate persona-authorized exception.
- **Health Metrics** stays ED-gated by design — this page does not migrate to a shared capability (LFXV2-2726 is evaluating an LF Staff answer, not yet started).
docs/architecture/frontend/permission-persona-navigation-model-preread.md:477
- The PR summary says this Model Asks section proposes removing the ED relation, but the changed spec now records the opposite resolved outcome: keep
executive_directoras the bundle for the named capabilities. Update the PR description so reviewers and linked-ticket readers are not given the superseded platform ask.
1. **Permission bundling for ED-derived capabilities — resolved: keep
`executive_director` as an FGA relation.** The app checks `auditor`,
`writer`, `marketing_auditor`, and `campaign_manager` directly and never
branches on the `executive_director` relation itself (see Writer Actions
above). Per Eric Searcy's review, the relation stays in the model rather
docs/architecture/frontend/permission-persona-navigation-model-preread.md:257
- This architecture doc reintroduces volatile implementation-status prose (
not yet startedon line 255 andin review as of this writinghere), which will become stale as soon as either ticket moves. The repository’s documentation checklist explicitly says to replace status trackers with stable implementation facts and ticket links (docs/reviews/docs-checklist.md:33-49). Keep the verified current guard behavior, but link the tickets without snapshotting their workflow state.
None of these three needs a new capability invented for it — the permissions already exist in the model. This migration is tracked in LFXV2-2236 ("Add Marketing Ops UI access (FGA guards)," in review as of this writing) — today, all three pages on `main` still gate solely on `executiveDirectorGuard` (a pure persona check with no FGA lookup). Until that ticket merges, treat "Current UI Facts" as describing the actual state, not this target state.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:9
- This “auditor is the only relation” rule conflicts with the selector contract repeated later as “auditor or explicit role grant.” The Core Principle defines an explicit role grant as any direct user-object tuple, and the live Project model has a concrete counterexample:
meeting_coordinator: [user]does not imply Projectauditor. Under line 9 that user cannot enter the Project context; under lines 208/270 and the companion matrix they can. Define which explicit relations qualify for context entry, or make the contract consistently auditor-only.
This issue also appears in the following locations of the same file:
- line 126
- line 255
- line 257
- line 473
- **Where can I go?** Outside of Me, `auditor` access (explicit or inherited) is what's needed to browse into a Foundation/Project/Organization context. It's the only relation that matters for context entry: any higher relation (writer, owner) includes `auditor` by inheritance.
Lexicon pass across both spec pages per the team's agreed vocabulary
(model / grants / permissions / guards / personas): retires "role" and
"grant bundle"/"bundling" except where quoting legacy code identifiers
or UI copy (cdp_roles' `role` field, the "Roles" filter chip) - both
marked legacy inline. "Relation" is retired wherever it meant an
evaluated permission ("the action-specific relation the API requires"
-> "the action-specific permission..."); it stays only where it
describes the model's own graph structure. "auditor or explicit role
grant" -> "auditor or another explicit permission" throughout. Core
Principle rewritten around the agreed doctrine sentence; the
role-as-bundle paragraph is gone, replaced by the one agreed line
("Grants and the model are the platform team's domain").
Compression pass: preread's Core Principle and terminology sections
(now a five-term Terminology section replacing the old Viewer/Auditor
discussion, folding those two in as permission examples) tightened
substantially; "Why This Is Needed" cut (it restated the TL;DR in new
words); "Current UI Facts" collapsed from narrative to a status table;
"Open Follow-Ups" folded into P3's regression-test bullets and cut
otherwise. Decision matrix keeps its scenario structure unchanged -
lexicon pass only.
Added the open Health Metrics question exactly as posed to Eric
Searcy (Model Ask #3): writer permission on a context should surface
Health Metrics too, via either a model change (writer feeds
marketing_auditor) or a guard change (Health Metrics accepts writer OR
marketing_auditor) - not resolved here.
Diagram replaced with the fully-relabeled ~/lfx/permission-model.svg
(GRANTS / evaluated by the model / PERMISSIONS / GUARDS / personas
outside the model). Two labels remain drifted from the doc text after
this pass - flagging rather than silently shipping the mismatch:
- Context Entry gate chip still reads "auditor / explicit role" (the
doc now says "auditor or another explicit permission").
- Create/Manage Actions gate chip still reads "action-specific
relation on target" (the doc now says "...permission on target").
Consistency grep: zero unmarked "role"/"bundle" instances in either
doc.
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
|
@emsearcy the lexicon pass is up (63a0a7e).
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (8)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:221
- Keeping Health Metrics behind the pure persona-based
executiveDirectorGuardin the target state contradicts the preceding “never on a persona guard” rule, the Core Principle, and the companion matrix's permission-only page-visibility rule. Since Model Ask #3 is unresolved, describe this as a current exception awaiting a named permission decision rather than a settled target, or qualify the permission-only contract.
- **Health Metrics** stays ED-gated by design — this page does not migrate to a shared permission (LFXV2-2726 is evaluating an LF Staff answer, not yet started; see also the open Paul/Jim question in Model Asks).
docs/architecture/frontend/permission-persona-navigation-model-preread.md:27
- This blanket prohibition still contradicts the next paragraph and the companion matrix, both of which require persona-driven presentation. Restrict it to authorization/data-access decisions so implementers are not told both to shape the UI by persona and never branch on persona.
This issue also appears on line 221 of the same file.
App code never branches on personas. Every gate is a permission check — can
user U do action A on object O. Guards define which permission each action
needs.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:132
- These examples revert to blanket
writerchecks immediately after documenting action-specific alternatives. Meeting organizers can derive authority from Meeting Coordinator or Committee Writer, and vote/survey writers can derive from the committee target, so these examples would mis-specify valid Me actions.
- **Pending agenda action:** resolve the target group/project/foundation; allow agenda management only if writer permission applies.
- **Meeting card:** open the meeting with its context; edit/manage only if writer permission applies.
- **Vote or survey:** open the item; view/results follow viewer/discoverable eligibility for that item, edit/close follows writer permission.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:212
canWrite()is the project-writer check, so this proposed target would discard the Meeting Coordinator and Committee Writer paths documented just above. Keep the target guard aligned with the spec's resolved-object/action-specific-permission contract.
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-navigation-model-preread.md:89
- The current-state inventory is inaccurate:
documents.routes.ts:7-12has onlyauthGuard, and the document toolbar is gated by project scope rather than either ED fast path. Conversely, Group/Committee create and edit routes do usewriterGuard. Correcting the route list matters because this table claims to be code-verified.
| ED fast path in `writerGuard`/`newsletter-access.guard.ts` | Needs verification (P0) | Skips the permission check for ED persona on meetings/votes/surveys/mailing lists/newsletters/document routes. Does not grant the write itself — API enforcement is separate, and `executive_director` does not inherit project `writer`. Very likely a guard bug (a misleading UI-only affordance a downstream write would reject), not a permission the model grants. Whether it's a confusing dead-end or an actual gap depends on independent API enforcement — see P0. |
docs/architecture/frontend/permission-persona-navigation-model-preread.md:480
- The stated baseline is wrong: Health Metrics currently checks the ED persona, not
marketing_auditoralone, and the earlier target text says it does not migrate to a shared permission. Make the first option include that guard migration and compare the second option with the actual ED eligibility.
imply. Two ways to close that gap: either `writer` starts feeding
`marketing_auditor` in the model, or the Health Metrics guard accepts
`writer` OR `marketing_auditor` instead of `marketing_auditor` alone.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:452
- The PR summary says this section proposes removing the ED relation and adding LF Staff Team inheritance for B2B Organization auditor access, but the added spec records the opposite outcomes: ED stays, and org-wide access uses distinct per-object global relations rather than project-style team/root inheritance. Update the PR description so reviewers see the decisions actually being proposed.
1. **`executive_director` stays as a grant in the model — resolved.** The
app checks `auditor`, `writer`, `marketing_auditor`, and
`campaign_manager` directly and never branches on the
`executive_director` grant itself (see Writer Actions above). Per Eric
Searcy's review, it stays rather than being removed or replaced — it
docs/architecture/frontend/permission-persona-decision-matrix.md:118
- The matrix says persona never decides whether a user can read page data, but the preread's target state keeps Health Metrics behind the pure persona-based
executiveDirectorGuard. Resolve or explicitly mark that exception in both specs; otherwise this companion matrix cannot be used as the target decision contract.
Persona changes what the experience looks like (layout, emphasis, copy,
ordering). It never decides whether the user can enter the context, read its
data, or write to it — those outcomes are stated below purely in permission
terms (auditor permission, writer permission, named permission).
Replace the parked Health Metrics open question with the decision from Slack (Eric + Manish, Jul 31-Aug 4): - Guards check a single permission; inheritance belongs in the model (Eric's rule) - no multi-permission ORs in any guard. - Health Metrics guards on auditor: anyone who can audit the context sees its health (auditor alone never implies write). - Marketing Impact guards on marketing_auditor; the model adds writer -> marketing_auditor so context writers see it without the guard knowing about writer (model change, platform team). - Campaigns stays guarded on campaign_manager (write authority is not implied by writer) - unchanged, just no longer framed as open. executiveDirectorGuard on these three routes is replaced by three single-permission guards, not a persona check or a multi-permission OR. Updated Writer Actions, Model Asks #3, and the Contract Summary; grepped both docs for open-question language - nothing left. LFXV2-2913 Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (2)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:212
- This collapses
writerGuardtocanWrite(), but the current guard also admitsproject.meetingCoordinatorandcommittee.writer, and this spec's own general rule requires the action-specific permission. Following this target would regress committee writers and meeting coordinators. Describe the current guard as the ED fast path plus its action-specific checks, and the target as resolved target object plus action-specific permission. The stale blanket wording also remains in P3/Contract Summary and in the companion matrix's line 58, which requires a Foundation/Project target while namingcommittee.writer.
Current writerGuard = Executive Director fast path or canWrite()
Target writerGuard = resolved target context + canWrite()
docs/architecture/frontend/permission-persona-navigation-model-preread.md:27
- This blanket prohibition contradicts the next paragraph and the companion matrix, which require persona-based presentation branching for layout, emphasis, copy, and ordering. The same overstatement appears in
permission-model.svgat lines 7 and 59. Limit the prohibition to access and action-authority decisions so implementers do not remove the presentation behavior this spec explicitly requires.
This issue also appears on line 211 of the same file.
App code never branches on personas. Every gate is a permission check — can
user U do action A on object O. Guards define which permission each action
needs.
…ecision Per Eric Searcy's second-round review: guards must check exactly one permission on the action's own resolved object; container-permission inheritance belongs in the model, not re-derived as an OR across project/committee/coordinator checks in the UI. - Me Lens target/permission paragraph (preread): reworked the PR #1193 create-flow explanation to distinguish create-time target resolution (one permission per chosen parent) from edit/manage of an existing item (one permission on the item's own object - a meeting checks `organizer`, which the model already inherits from Project Meeting Coordinator, Committee Writer, and Project Writer). - Examples bullets (preread): "Pending agenda action" -> "Pending action item," permission validated per action-item type (agenda itself has no writeable action); "Meeting card" and "Vote or survey" now name the single permission checked; "Akrites package" flagged explicitly as an exception to the OpenFGA model (no package/stewardship relation exists). - ED-shortcut paragraph (preread): removed the "unless the user also has writer permission" carve-out - there is no authorization shortcut, full stop. - Decision matrix: reworded the meeting write-candidate/existing-item permission language to `organizer`; split the Meetings Create/manage bullet into Create (single permission on the chosen target) and Manage-existing (single `organizer` check on the meeting); reworded Votes and Surveys Create/manage bullets to drop the literal "OR" guard phrasing in favor of "permission on the chosen target." Health Metrics guard decision (Eric's threads asking whether Health Metrics needs an additional staff-only AND-guard) was already recorded in the prior commit (9cdce56): guards on `auditor` alone, no AND-staff guard - anyone who can audit the context sees its health. Diagram: synced permission-model.svg from the design source - card 4 now reads "the action's own permission on its object" with the meeting -> organizer example. Same pre-existing lexicon drift as flagged in the prior round remains baked into the SVG's own labels ("auditor / explicit role" contains "role"; "executive_director relation" and "evaluated relationships" contain "relation") - not hand-edited per established precedent (commit af714dd); flagging here again since the retired terms are still present. Consistency grep for guard-level "OR" language across both docs found none remaining outside this explanatory paragraph itself. LFXV2-2913 Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
Round 2 review feedback addressedCommit: 8ba162f Changes made (per @emsearcy)
Note on the diagramSame pre-existing lexicon drift flagged in the prior round is still baked into the SVG's own labels ("auditor / explicit role" contains "role"; "executive_director relation" / "evaluated relationships" contain "relation"). Not hand-edited per established precedent (af714dd) — flagging again since it's still there. Threads resolved8 of 8 unresolved threads addressed and resolved in this iteration. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (7)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:126
- This describes the shipped flow as already making one permission check, but current
writerGuardseparately testsproject.writer, thenproject.meetingCoordinator, and thencommittee.writerwhen applicable (writer.guard.ts:80-100). The companion current-state matrix also records the API's project permission asmeetings_creator. Distinguish the current multi-check UI guard from the target singlemeetings_creatorcheck; otherwise the spec marks the migration as complete when it is not.
`committee_uid` is present, and accepts `project.meeting_coordinator` when
the target is a project and no meeting object exists yet — each create
checks exactly one permission on the chosen parent, never several checked
together.
docs/architecture/frontend/permission-persona-decision-matrix.md:212
- This target rule still lists the underlying
writer/meeting_coordinatorsources and then says only one permission is checked. The API contract already exposes the resolved project action asmeetings_creator(persona-content-matrix.md:193); the target should check that on a project/foundation target, orwriteron a committee target. Keeping the source relations here would preserve the multi-permission OR that the spec explicitly rejects.
- **Create:** Requires the create-granting permission on the chosen target — `writer` or `meeting_coordinator` when the target is a Project, `writer` when the target is a Foundation, `committee.writer` when the target is a committee/group. One permission checked on the chosen target, not several checked together.
docs/architecture/frontend/permission-persona-decision-matrix.md:248
- As with Votes, this collapses parent-scoped creation and item-scoped management even though the document's core rule says existing actions check the item's own resolved permission. This would direct implementers to keep checking the project/committee when editing or closing an existing survey instead of checking the survey relation enforced by its API.
- **Create/manage:** Requires the create-granting permission on the chosen target — `writer` when the target is Foundation/Project, `committee.writer` when the target is a committee/group.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:27
- The current wording still prohibits all persona branching, but this spec immediately defines personas as the input for presentation branching, and the app currently does exactly that for sidebar composition (
sidebar-nav.service.ts:307). Narrow this principle to authorization/access decisions so implementers do not read the target model as forbidding the presentation behavior the document requires.
This issue also appears on line 123 of the same file.
App code never branches on personas. Every gate is a permission check — can
user U do action A on object O. Guards define which permission each action
needs.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:89
- This current-state inventory does not match the route table.
writerGuardalso protects committee/group create and edit routes (committees.routes.ts:16-30), while document routes use onlyauthGuard(documents.routes.ts:7-13) and the document toolbar is enabled solely by project scope (documents-dashboard.component.ts:105-110). Including documents under this ED fast path while omitting committees hides the actual document authorization gap and gives the P0 audit the wrong scope.
| ED fast path in `writerGuard`/`newsletter-access.guard.ts` | Needs verification (P0) | Skips the permission check for ED persona on meetings/votes/surveys/mailing lists/newsletters/document routes. Does not grant the write itself — API enforcement is separate, and `executive_director` does not inherit project `writer`. Very likely a guard bug (a misleading UI-only affordance a downstream write would reject), not a permission the model grants. Whether it's a confusing dead-end or an actual gap depends on independent API enforcement — see P0. |
docs/architecture/frontend/permission-persona-decision-matrix.md:100
- The model does not make the current guard's two relation checks into “one resolved permission”: the code explicitly checks
writerand thenmeeting_coordinator(writer.guard.ts:80-100). The existing current-state matrix names the API relation asmeetings_creator(persona-content-matrix.md:193). Name that action permission as the target and state thatwriterGuardstill needs migration, rather than claiming the current guard already performs the target check.
This issue also appears on line 212 of the same file.
- **Required permission:** User must choose a target object (project, foundation, committee, or group), then the action-specific permission on that object must pass. For most creates the target is Foundation/Project and the permission is `writer`. For Create Meeting, Create Survey, and Create Vote, the target can also be a committee/group, authorized by `committee.writer`. Create Meeting's project-target check is a single permission — the model grants project-level meeting-creation authority to both `project.writer` and `project.meeting_coordinator`, so the guard checks the one resolved permission, never two separate calls in the UI.
docs/architecture/frontend/permission-persona-decision-matrix.md:241
- Combining create and manage here contradicts this spec's existing-item rule at lines 92–95 and the preread's rule that an existing item's own permission is authoritative. A committee writer may authorize creation through the parent, but management of an existing vote should check the permission resolved on that vote, not re-derive the parent grant.
This issue also appears on line 248 of the same file.
- **Create/manage:** Requires the create-granting permission on the chosen target — `writer` when the target is Foundation/Project, `committee.writer` when the target is a committee/group.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (4)
docs/architecture/frontend/permission-persona-navigation-model-preread.md:9
- The permission-only rule includes Organization, but the target never accounts for current Board Member Org access.
AccountContextService.hasOrgSelectorAccessaccepts persona-seeded accounts (account-context.service.ts:68-76), and those accounts come fromboard_memberdetections (persona-detection.service.ts:418-440); Model Ask #2 only creates Org permissions for LF staff. Applying this rule as written would therefore remove Board Members from their organizations. Either scope this statement to Foundation/Project or define how Board Member organizations receive a named Org permission and add the corresponding Org cases to the matrix.
- **Where can I go?** Outside of Me, `auditor` permission (direct or inherited via the model) is what's needed to browse into a Foundation/Project/Organization context. It's the only permission that matters for context entry: any higher permission (writer, owner) includes `auditor` by inheritance.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:89
- The current-state route inventory is inaccurate. Document routes use only
authGuard(documents.routes.ts:7-12), while the ED fast path actually affectswriterGuardroutes for meetings, surveys, votes, mailing lists, and committees, plus newsletter manager routes. Including documents while omitting committees makes the P0 audit scope incomplete; update this row to match the mounted guards.
| ED fast path in `writerGuard`/`newsletter-access.guard.ts` | Needs verification (P0) | Skips the permission check for ED persona on meetings/votes/surveys/mailing lists/newsletters/document routes. Does not grant the write itself — API enforcement is separate, and `executive_director` does not inherit project `writer`. Very likely a guard bug (a misleading UI-only affordance a downstream write would reject), not a permission the model grants. Whether it's a confusing dead-end or an actual gap depends on independent API enforcement — see P0. |
docs/architecture/frontend/permission-persona-decision-matrix.md:100
- This says the UI performs one resolved permission check, but
writerGuardcurrently checksproject.writerand then separately requestsmeeting_coordinatorfor non-writers (writer.guard.ts:80-95), while the code-verified current-state matrix identifies the API's composed Project permission asmeetings_creator(persona-content-matrix.md:188-193). If the target is one action relation, namemeetings_creatorand describe the current UI OR as migration work; otherwise remove the one-check claim. The same inconsistency appears at line 212 and in the preread at lines 122-126.
- **Required permission:** User must choose a target object (project, foundation, committee, or group), then the action-specific permission on that object must pass. For most creates the target is Foundation/Project and the permission is `writer`. For Create Meeting, Create Survey, and Create Vote, the target can also be a committee/group, authorized by `committee.writer`. Create Meeting's project-target check is a single permission — the model grants project-level meeting-creation authority to both `project.writer` and `project.meeting_coordinator`, so the guard checks the one resolved permission, never two separate calls in the UI.
docs/architecture/frontend/permission-persona-navigation-model-preread.md:27
- The current wording still prohibits every persona branch, contradicting the next paragraph and the companion matrix's rule that persona drives presentation. It also rules out the intended dashboard/sidebar composition visible in
dashboard.component.ts:54-57andsidebar-nav.service.ts:313. Limit the prohibition to access and action gating; presentation code must remain allowed to branch on persona. The diagram repeats the same absolute wording on line 7.
App code never branches on personas. Every gate is a permission check — can
user U do action A on object O. Guards define which permission each action
needs.
Summary
writer.guard.ts/newsletter-access.guard.tsas likely a bug perPERMISSIONS.md.Docs-only change, no application code touched.
LFXV2-2913
Test plan
yarn prettier --checkon both changed filesyarn lint:check(no errors; pre-existing unrelated warning only)