Table of Contents

Class ScopeDefinition

Namespace
Tharga.Team
Assembly
Tharga.Team.dll

Defines a scope with its default minimum access level and an optional human-readable description (shown as a tooltip in the scope picker).

public record ScopeDefinition : IEquatable<ScopeDefinition>
Inheritance
ScopeDefinition
Implements
Inherited Members

Remarks

A scope name follows a grammar, and it is load-bearing rather than cosmetic.

{feature}:{action}            team:read, apikey:manage, audit:read, mcp:discover
{feature}:{reach}:{action}    support:unassigned:read, support:all:read

Feature is the area acted on and action is what may be done — the two halves the audit log already names, filters and charts by. Reach names the population a grant covers, and is present only where that population is not the one the scope is held against. A team scope needs no reach segment: it is held against a team, and that team is its reach. A system scope has no team to imply one, which is why every reach-bearing scope today is a system scope.

The first colon is the one that matters. AuditEntry.ParseScope splits there and nowhere else, so support:all:read is audited as feature support, action all:read. That is why reach goes in the middle: moving it into the feature — support-all:read — would fork one feature into two in the audit log's feature filter and its charts, and would fall outside a support:* notification route.

Two scopes express reach differently and are not the shape to copy. teams:read pluralises the feature to mean "every team", against team:read's one; apikey:system-manage qualifies the action instead. Both predate the grammar, and neither is worth renaming: a renamed scope is invisible to the compiler and silently authorizes nothing.

Constructors

ScopeDefinition(string, AccessLevel, string, bool)

public ScopeDefinition(string Name, AccessLevel DefaultMinimumLevel, string Description, bool GrantOnly)

Parameters

Name string
DefaultMinimumLevel AccessLevel
Description string
GrantOnly bool

ScopeDefinition(string, AccessLevel, string, bool, string)

Defines a scope with its default minimum access level and an optional human-readable description (shown as a tooltip in the scope picker).

public ScopeDefinition(string Name, AccessLevel DefaultMinimumLevel, string Description = null, bool GrantOnly = false, string Group = null)

Parameters

Name string

The scope name, as checked by RequireScopeAttribute. See the remarks for the grammar it follows.

DefaultMinimumLevel AccessLevel

The least-privileged access level that is granted this scope automatically. Meaningless when GrantOnly is true, since no access level grants such a scope.

Description string

Human-readable description, shown in the scope catalogue and pickers.

GrantOnly bool

When true the scope is registered for documentation and validation only: no access level grants it, a tenant-defined custom role may not reference it, and the scope-override pickers do not offer it. It is held solely through a code-registered tenant role or an explicit scope override, so holding it is a recorded decision rather than a consequence of being a team Owner or Administrator. Register one with RegisterGrantOnly(string, string).

Group string

The key of the ScopeGroup the scope is shown under, or null for an ungrouped scope. Display only: it has no bearing on who holds the scope or how it is checked.

Remarks

A scope name follows a grammar, and it is load-bearing rather than cosmetic.

{feature}:{action}            team:read, apikey:manage, audit:read, mcp:discover
{feature}:{reach}:{action}    support:unassigned:read, support:all:read

Feature is the area acted on and action is what may be done — the two halves the audit log already names, filters and charts by. Reach names the population a grant covers, and is present only where that population is not the one the scope is held against. A team scope needs no reach segment: it is held against a team, and that team is its reach. A system scope has no team to imply one, which is why every reach-bearing scope today is a system scope.

The first colon is the one that matters. AuditEntry.ParseScope splits there and nowhere else, so support:all:read is audited as feature support, action all:read. That is why reach goes in the middle: moving it into the feature — support-all:read — would fork one feature into two in the audit log's feature filter and its charts, and would fall outside a support:* notification route.

Two scopes express reach differently and are not the shape to copy. teams:read pluralises the feature to mean "every team", against team:read's one; apikey:system-manage qualifies the action instead. Both predate the grammar, and neither is worth renaming: a renamed scope is invisible to the compiler and silently authorizes nothing.

Properties

DefaultMinimumLevel

The least-privileged access level that is granted this scope automatically. Meaningless when GrantOnly is true, since no access level grants such a scope.

public AccessLevel DefaultMinimumLevel { get; init; }

Property Value

AccessLevel

Description

Human-readable description, shown in the scope catalogue and pickers.

public string Description { get; init; }

Property Value

string

GrantOnly

When true the scope is registered for documentation and validation only: no access level grants it, a tenant-defined custom role may not reference it, and the scope-override pickers do not offer it. It is held solely through a code-registered tenant role or an explicit scope override, so holding it is a recorded decision rather than a consequence of being a team Owner or Administrator. Register one with RegisterGrantOnly(string, string).

public bool GrantOnly { get; init; }

Property Value

bool

Group

The key of the ScopeGroup the scope is shown under, or null for an ungrouped scope. Display only: it has no bearing on who holds the scope or how it is checked.

public string Group { get; init; }

Property Value

string

Name

The scope name, as checked by RequireScopeAttribute. See the remarks for the grammar it follows.

public string Name { get; init; }

Property Value

string