Skip to content

Show in the explain panel how a realm treats callers who aren't signed in - #809

Merged
habdelra merged 7 commits into
mainfrom
cs-13609-policy-explain-what-a-realm-does-with-a-caller-who-isnt
Oct 6, 2026
Merged

habdelra merged 7 commits into
mainfrom
cs-13609-policy-explain-what-a-realm-does-with-a-caller-who-isnt

Conversation

@habdelra

@habdelra habdelra commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Important

Merge order: #808, then cardstack/boxel#6579, then this PR, then cardstack/boxel#6581.
This is stacked on #808 and changes realm-policy/realm-policy.gts, a file in boxel's catalog test subset. Retarget it to main once #808 merges. It merges after boxel#6579, so that #6579's pin, #808's head, still matches catalog main when #6579 merges. The paired boxel PR pins this PR's head.

Merges before: cardstack/boxel#6581

In service of CS-13521, which lets a realm's policy admit a caller who isn't signed in. Boxel's explain now reports, for such a caller, how the realm limits and blocks them, who each grant opened to them writes as, and what compiling the policy recorded against each grant. This PR shows that in the explain panel:

  • A "Limit" row: "N requests per S seconds from one address, set by this realm" or "the platform default".
  • A "Blocklist" warning when the realm's blocklist has an entry that isn't an address or a range, since that closes the realm to everyone who isn't signed in.
  • A line on each grant opened to such callers: the user its writes are made as and the realm setting that names them, or why that setting names no one ("this realm's settings have no …", "… isn't a user ID", "… can't write to the realm").
  • Each grant's own issues, as warning pills with their messages.

The panel reads these fields where an explanation carries them, through a local widening of the explanation type, so it answers the same on a platform that doesn't report them. That is what lets it merge ahead of the boxel PR that adds them.

🤖 Generated with Claude Code

habdelra and others added 3 commits October 6, 2026 16:25
…d in, who each grant opened to them writes as, and each grant's own issues

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…an-anonymous' into cs-13609-policy-explain-what-a-realm-does-with-a-caller-who-isnt
…an-anonymous' into cs-13609-policy-explain-what-a-realm-does-with-a-caller-who-isnt

@habdelra habdelra left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Independent review of this PR

I compared the local widening against boxel's ExplainedAnonymousAccess, ExplainedGrant.anonymous and ExplainedGrant.issues on the paired branch, and it matches exactly: limit {requests, windowSeconds}, limitFrom 'realm'|'platform', invalidBlocklistEntries: string[], actingUserKey?/actingUser?/actingUserFailure?: 'key-missing'|'not-a-matrix-id'|'no-write', and issues?: PolicyIssue[] (the same type DraftIssue resolves to). The {{#let (this.grantDetail grant)}} cast, MessageText and the Pill @tag='span' warning colors follow patterns already in the file. The new .grant-note and .grant-issue rows take flex-basis: 100%, so they wrap below the existing .matched-grant flex row (which already has flex-wrap: wrap) and leave it intact. Comments carry no ticket IDs or history. I found no blockers. The inline comments cover the Blocklist row's warning styling, wording, and a pluralization nit.

Not tied to a line:

  • minor, description: the description says "the paired boxel PR pins this PR's head" but doesn't name that PR, and has no Merges before: cardstack/boxel#N line under the callout. #808 has its own. The boxel branch exists and pins this head, but no PR is open for it yet. Once one is open, name it in the callout and add the pairing line, because the pairing checks in both repositories read that line.
  • minor, test coverage on the paired boxel branch: I traced the host test an explanation for someone who is not signed in shows the limit, and who each grant opened to them writes as against this code. Its exact strings match what the panel renders: 7 requests per 30 seconds from one address, set by this realm, plus both data-test-explanation-grant-anonymous lines for submitter→user and missing→key-missing. Nothing exercises data-test-explanation-anonymous-blocklist, data-test-explanation-grant-issue, the the platform default branch, or the not-a-matrix-id/no-write messages. The Blocklist row matters most of these because it's the one that warns a realm is closed. Please add an assertion for it, and for one grant-issue row.
  • nit, follow-up: after the paired boxel PR merges and the platform types carry these fields, the AnonymousAccessDetail/GrantAnonymousDetail/ExplainedGrantDetail widening and the grantDetail identity cast are no longer needed. If they're meant to be removed later, that needs a ticket linked from the description, per the deferred-follow-up rule.

Comment thread realm-policy/realm-policy.gts Outdated
<dd data-test-explanation-anonymous-limit>{{this.anonymousLimit}}</dd>
{{#if this.anonymousAccess.invalidBlocklistEntries.length}}
<dt>Blocklist</dt>
<dd class='warning' data-test-explanation-anonymous-blocklist>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] minor: this row is meant to read as a warning, but .facts .warning only sets color: var(--warning-foreground, …). --warning-foreground is the text color for content sitting on a --warning fill (that's how the grant-issue Pill below uses it), so on the card's own background it renders as ordinary body text in a light theme and can drop to low contrast in a theme whose warning foreground is dark. Nothing visual or semantic marks the row as a warning, and this case is the one that closes the realm to every caller who isn't signed in. Suggested fix: lead the dd with the same warning Pill the grant issues use (@pillBackgroundColor='var(--warning, var(--boxel-warning))' …, text warning) and drop the .facts .warning color rule, so the cue is the same everywhere in the panel and isn't carried by color alone.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in 783dc306. The Blocklist row leads with the same warning Pill the grant issues use, so the cue matches the rest of the panel and isn't carried by color alone.

Comment thread realm-policy/realm-policy.gts Outdated
align-items: baseline;
gap: var(--boxel-sp-xs);
}
.facts .warning {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] minor: see the Blocklist row. --warning-foreground is a foreground-on-warning-fill token, not a warning text color, so this rule doesn't do what the class name says. Remove it in favor of a warning Pill on the row, or, if a text color is wanted, use a token meant for text on the page background.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in 783dc306. The .facts .warning rule is gone; the row's Pill marks it.

margin: 0;
font-size: var(--boxel-font-size-xs);
font-weight: normal;
color: var(--muted-foreground, var(--boxel-450));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] nit: .grant-issue shares the muted, extra-small styling with .grant-note, so a compile warning's message renders dimmer than the grant's own outcome label next to it. DraftIssues and the edit-view grant warnings show issue messages in the normal foreground. Suggest keeping color: var(--muted-foreground, …) on .grant-note only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in 783dc306. Only .grant-note is muted. An issue's message renders in the normal foreground, as DraftIssues does.

Comment thread realm-policy/realm-policy.gts Outdated
return '';
}
let { requests, windowSeconds } = access.limit;
return `${requests} requests per ${windowSeconds} seconds from one address, ${

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] nit: no pluralization, so a limit of one gives "1 requests per 1 seconds from one address". anonymousRateLimit accepts any positive integer, so a realm that sets 1 request or a 1-second window will show this. Suggest choosing request/requests and second/seconds from the count.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in 783dc306. counted() picks request/requests and second/seconds from the count.

Comment thread realm-policy/realm-policy.gts Outdated
if (anonymous.actingUserFailure) {
return `${opened}, but ${ACTING_USER_FAILURES[anonymous.actingUserFailure](key)}`;
}
return `${opened}, writing as ${anonymous.actingUser} (the realm's "${key}" setting).`;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] minor: two wording points on the acting-user line. (1) The grant detail is attached for every actor (detailer in boxel's explain.ts adds anonymous whether or not the caller is signed in), so a signed-in teacher's explanation also reads "writing as @x (the realm's "submitter" setting)", which suggests the teacher's own writes go out as that user. Something like "Open to people who aren't signed in; their writes are made as @x (this realm's "submitter" setting)." says whose writes. (2) If actingUserKey is present with neither actingUser nor actingUserFailure, this renders "writing as undefined". boxel never sends that shape today, but the panel is written to tolerate platforms that differ, so guarding anonymous.actingUser costs nothing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in 783dc306. The line now says whose writes it means: "Open to people who aren't signed in; their writes are made as @x (this realm's "submitter" setting)." A key with neither a user nor a failure reads "…made as whoever this realm's "key" setting names" instead of rendering undefined.

Comment thread realm-policy/realm-policy.gts Outdated
(key: string) => string
> = {
'key-missing': (key) =>
`this realm's settings have no "${key}", so it admits none of them.`,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] nit: "so it admits none of them": "it" reads as the realm (the subject of the clause is "this realm's settings"), but it's the grant that admits no one. The realm may still admit anonymous callers through other grants. Suggest "so this grant admits none of them" in all three messages (here, 762, 764).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in 783dc306. All three messages say "so this grant admits none of them".

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Staging Submissions Preview

This PR's content is pushed to the staging submissions realm: https://realms-staging.stack.cards/submissions/

Changed folders:

  • realm-policy/

Updated at 2026-10-06 21:21:43 UTC for commit 708a033. Shared realm: only this PR's changed files are pushed; files touched by multiple PRs reflect whichever pushed last, and deleted files are not removed.

…ant makes, and count limits in the singular

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@habdelra

habdelra commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

[Claude Code 🤖] On the review's line-less findings:

  • Pairing: the paired PR is Policy: explain how a realm treats a caller who isn't signed in boxel#6581. The callout names it, and Merges before: cardstack/boxel#6581 sits below the callout.
  • Host coverage: assertions for the Blocklist row and a grant-issue row are going into #6581's host test once that PR's own review reports, along with the new wording.
  • The local type widening: it stays. It's what lets this panel answer the same on a deployment whose platform doesn't report these fields, which is true of any older platform the catalog is served against, not only until #6581 merges. Once the platform types carry them, the intersection is redundant but harmless, so no removal is planned.

habdelra and others added 3 commits October 6, 2026 16:56
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…line as prettier wants it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@habdelra
habdelra requested a review from a team October 6, 2026 21:27
@habdelra
habdelra changed the base branch from cs-13605-policy-let-a-grant-on-a-named-operation-admit-an-anonymous to main October 6, 2026 23:22
@habdelra
habdelra merged commit 1c5b4cb into main Oct 6, 2026
20 of 21 checks passed

This branch was successfully deployed

1 active deployment
production — 708a0332 Deployed Oct 7, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants