Conversation
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
from
September 2, 2026 02:16
6f7b6ae to
faf6f53
Compare
barborico
marked this pull request as ready for review
September 2, 2026 02:39
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
from
September 2, 2026 19:53
faf6f53 to
572dff2
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
2 times, most recently
from
September 2, 2026 20:50
601f823 to
c129dae
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
from
September 2, 2026 21:11
c129dae to
0d16b92
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
2 times, most recently
from
September 9, 2026 00:37
70acdbe to
e83c857
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
2 times, most recently
from
September 9, 2026 22:31
72f2c09 to
f91183d
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
from
September 10, 2026 21:14
f91183d to
5b3d3e5
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
from
September 10, 2026 23:28
5b3d3e5 to
f98ca42
Compare
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
2 times, most recently
from
September 11, 2026 00:00
0fe866b to
b7f92d5
Compare
Base automatically changed from
brynna/drive_dialogs_off_effective_constraints
to
main
September 11, 2026 00:12
A group page listed the tags on it, which for a role is not the same question as what constrains it: a role's limits mostly arrive from the groups it is a member or owner of, and a tag on an app reaches every one of its groups. Someone asking why they cannot grant a year of access had to work that out from the tag list. The panel names each constraint in force, its coalesced value, and the tags it came from -- each with how it reached this group, so a reader can tell one they could lift by untagging here from one they cannot. It reads `effective_constraints` off the group detail, so it costs no request, and it collapses by default since most readers are not asking. Route the day formatting through one helper while adding it. Ten sites rendered `Math.floor(seconds / 86400) + ' days'`, which prints "0 days" for any limit under a day -- reading as no access at all, where the true answer is an hour -- and "1 days" for exactly one. The panel would otherwise contradict the dialog on the same page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A source row named the site the constraint came through but only linked the tag. The name is the more useful destination of the two: a reader following one is asking what that group or app is, and had to go find it by hand. An app origin links to the app rather than a group, which is why the API names those fields for the origin instead. A source whose app has since been soft-deleted still states its origin and stays unlinked, having no name to point at. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rendering a flag as its name alone is only right because the API omits one that is switched off. Say so, and name the helper that guarantees it: the tag form writes all four boolean keys on every save, so the response would otherwise be full of `False` flags and each would render as a restriction in force.
The app renders MUI through Emotion, which vitest resolves, so the components import under test and the stand-ins that stood for them are no longer needed. Rendering the real accordion means its contents start collapsed and out of the accessibility tree, so the assertions now open the panel the way a reader does before looking at a row. That is the behaviour the panel actually has, and the stand-ins could not express it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
barborico
force-pushed
the
brynna/effective_constraints_panel
branch
from
September 11, 2026 00:15
b7f92d5 to
d79daa2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Urgency: 5 days; does not need to deploy alongside the rest of the stack
Expected review effort: MEDIUM
Motivation
Make it obvious what constraints apply to a group and why.
A group page lists the tags on it, which for a role is not the same question as what constrains it. A role's limits mostly arrive from the groups it is a member or owner of, and a tag applied to an app reaches every one of that app's groups. Someone asking why they cannot grant a year of access had to work that out from a tag list and a mental model of propagation.
What's Changing
A collapsed Effective constraints panel on the group detail page. Each row names a constraint in force, its coalesced value, and the tag it came from — with how that tag reached this group:
directvia app Foovia membership in Foovia ownership of FooThat last distinction is the point: it separates a constraint a reader could lift by untagging this group from one they cannot.
The panel reads
effective_constraintsoff the group detail the page already fetched, so it costs no request of its own, and it collapses by default since most readers are not asking.The collapsed panel:

A directly applied constraint on a group:

Propagated constraints on a role:

Inherited constraints on an app group:

One piece of copy cleanup that came with it
Ten places rendered a time limit as
Math.floor(seconds / 86400) + ' days'. That prints "0 days" for any limit under a day — which reads as no access at all, where the true answer is an hour — and "1 days" for exactly one day.The panel formats the same values, so leaving this alone would have had a dialog and the panel above it disagree on the same page about the same group. All ten now use one
timeLimitLabelhelper, which renders<1 day,1 day,7 days.The tag form's seconds-to-days conversion is untouched — that one populates an editable number field rather than prose, and rounding there is a separate question.
Validation of Changes
13 new frontend tests. Ten cover the panel: the empty case renders nothing, the summary count, a time limit folded into the constraint column, a boolean rendered without a redundant "— Yes", the tag link and origin text, singular/plural/sub-day formatting, an unrecognised origin echoed rather than mislabelled as
direct, and a source entry withsourcesomitted (optional per the API contract). Three covertimeLimitLabeldirectly.The panel's test stands in plain DOM for MUI, as the other component tests here do — this repo's style engine cannot be loaded under vitest — while forwarding
Link'scomponent/toprops to the real router link, so the link assertion exercises rendered output rather than a mock.Verified in a browser:
The guard at the call site is deliberate and measured, not redundant with the panel's own empty check: without it the wrapping grid item still contributes its own 24px of padding, adding a gap to every group that has no constraints — which is most of them.
958 backend / 79 frontend passing;
ruff,ty,tsc, and prettier clean.🤖 Generated with Claude Code