Repository navigation
Administration and Access Control
Current release policy (28 October 2026): Guest game and GitHub admin PWA supersedes the public-install/OpenAI/multi-account delegation scope below. Public play is guest-only; only verified sharpninja administers through GitHub, and only admin remains installable. The following original design and approval evidence is historical and does not approve the changed release.
Implementation extension requested 27 October 2026, after the completed Phase 0–6 baseline. Historical phase approvals remain historical evidence; this extension receives its own hostile validation.
/admin provides a searchable moderation queue with pending, appealed, approved and completed filters, reasoned approval/rejection, independent appeal resolution, complete curation forms and decision history. /admin/words provides category/search filters, pair creation and editing (prompt, target, accepted alternatives and exactly three ordered hints), and exclusion from future rounds with a reason. /admin/users provides profile search, current roles, audited grants/revocations and role history. Ordinary players receive an access-denied state; private data is never fetched through an unrestricted admin endpoint.
| Role | Moderate and curate | Author/edit pairs and hints | Resolve appeals | Assign/revoke roles |
|---|---|---|---|---|
| Player | No | No | No | No |
| Moderator | Yes | Yes | No | No |
| Senior moderator | Yes | Yes | Yes | No |
| Administrator | Yes | Yes | Yes | Yes |
Appeal reviewers must remain independent of the proposer and original reviewer, even when they are administrators. Roles are additive; revoking one role does not revoke another role's permissions. The default player role cannot be assigned or removed. There is no browser-side self-grant or public administrator-bootstrap endpoint.
WORDPAIRS_ADMIN_PROFILE_IDS is a server-only comma-separated list of existing, stable profile IDs. It is never exposed as a public environment variable or accepted in HTTP input. The authenticated profile screen displays the current profile ID so an operator can configure the first administrator. Configured administrators receive the admin role in trusted identity/content composition and SQL access checks; the entire allowlist is never returned to a client. Their administrator permission cannot be revoked through the UI. Changing the allowlist requires restarting/redeploying the server. Other administrator and moderator grants persist in PostgreSQL and are reloaded on every authenticated request.
FR-ADMINPAGES-023/FR-23-C05 requires administration links to follow the same
permission matrix. The private, no-store session response projects only the
current actor's effective permissions; it never exports the bootstrap allowlist,
provider subject or server role context. Anonymous and ordinary player sessions
render no administration links, including on direct /admin entry. Moderators
can navigate to moderation and word pairs/hints; only administrators see users
and access. Existing route/application/SQL checks remain authoritative for every
read and write.
The identity panel refreshes permissions every15 seconds and on tab focus.
Failed refreshes remove links. Session mutations retire prior reads and clear
navigation immediately; focus/poll refreshes cannot overtake a pending guest
entry or sign-out. Successful guest entry reloads the verified session before
showing any permission-based links. Missing permission fields fail closed.
tests/browser/auth-navigation.phase6.spec.ts covers the rendered role matrix,
direct entry, revocation, failure and logout. Deferred POST/DELETE regressions in
tests/web/identity-navigation.test.ts verify focus cannot restore an old session.
flowchart LR
UI[Admin pages] --> HTTP[Authenticated route handlers]
HTTP --> ACL[Access service]
HTTP --> Content[Content service]
Env[Server-only admin profile IDs] --> Identity[Trusted identity and role context]
Identity --> ACL
Identity --> Content
ACL --> Exclusive[Exclusive ACL transaction lock]
Content --> Shared[Shared ACL transaction lock]
Exclusive --> Roles[(Roles, revision, retry records, audit)]
Shared --> Fresh[Reload authoritative roles]
Fresh --> Catalog[(Moderation aggregate, immutable catalog, audit, outbox)]
The ACL has a singleton revision and a dedicated serialized change transaction. Only a current administrator can read the user directory or change roles. A role change validates the target profile, role, grant/revoke intent, reason, command ID, digest and expected ACL revision; it atomically writes the role, revision, canonical retry result and append-only audit record. Changed command digests and stale revisions reject. Removing the final effective administrator is rejected, considering configured administrators whose profiles exist. Concurrent cross-revocations serialize so they cannot remove every administrator. Revoked actors cannot use old ACL commands to regain authority.
ACL mutations take an exclusive advisory transaction lock; privileged content mutations take the corresponding shared lock before loading authoritative roles. This establishes a single order for content writes racing with revocation. Content then follows the existing room/match/moderation/catalog lock order. Revocation denies new privileged commands; an exact replay of an already committed content command retains its existing mutation-free canonical response.
Database functions are executable only by service_role. ACL tables have RLS enabled and deny browser roles, and privileged changes never depend on roles, wins or actor IDs supplied by the client. HTTP mutation routes require the canonical same-origin checks, a valid session, expected profile binding, strict field allowlists and no-store responses. Search results are bounded and include only profile ID, generated alias, identity kind and effective roles; they exclude credentials, email and OIDC subjects.
Edits append the next immutable version of an existing pair; creation uses a new ID at version zero. Existing pair IDs cannot move between categories. All saves require a reason, valid approved category/background, bounded plain text, accepted alternatives and exactly three hints. The existing moderation aggregate serializes publication, audits, exclusions and catalog-revision invalidation in one database transaction. New records flow through the existing catalog projection trigger.
Community activation creates only previously unused pair IDs at version zero. It cannot reuse an existing pair ID in another category or skip versions; revisions belong to the editorial save path.
Active rounds continue using their original pair ID and version. Future pools choose the highest version per pair ID and include it only if that version is selectable; excluding it never falls back to an older version. Exclusion preserves historical records and cannot empty an initial category. A revised excluded pair is a new selectable version; older exclusions remain in history. Direct editorial authoring is a privileged, audited operation; community proposals continue through the existing independent review and activation workflow and cannot have their status silently overridden. There is no destructive delete operation.
The existing catalog ceiling counts every approved historical pair version. Under the serialized moderation transaction, both direct saves and community activations must check the projected total before publishing: adding beyond 4096 versions returns SERVICE_LIMIT without state, audit, revision or idempotency writes. This includes editing an existing pair at the ceiling. A rejected edit leaves historical lookups and active games available.
Pure policy and transport tests cover permission inheritance, configured administrators, input/identity/origin forgery, content revisions and invalid hints. Real PostgreSQL tests cover role grants, revocations, idempotency, concurrent final-administrator removal, role changes racing with content, audit atomicity, browser-role denial, immutable old content and new-round selection. Browser tests exercise ordinary-player denial, administrator role management, moderation, editable word/hint forms, uncertain retry and phone layout. Existing unit, integration, browser, type, lint and production-build checks remain applicable. Independent hostile review examines the design and the exact final change/evidence, and records unresolved findings rather than inventing user sign-off gates.
The UI implementation design and evidence extends the existing authority and immutable-catalog boundary with reasoned changes_requested/resubmit and on_hold/resume transitions. Migration011 retains legacy pending records while adding pending_review and extending the one-open-suggestion index. The proposer-only revision path never bypasses independent review, curation or the rejection appeal policy. Actor, prior/new proposal, case version, reason and status are committed in the same audit transaction.
Tab-local drafts, verified session generations, native profile Save/Cancel/Escape, canonical uncertain-command retention and acknowledged success results now survive authorized in-tab navigation. Authorization denial invalidates older reads before private data can return. The existing live room transport remains separately verified; fixture browser UI evidence does not establish the full real private-push player-count matrix.
Generated from MCP requirements wiki export.
- Home
- Guest Game and GitHub Admin PWA
- Functional Requirements
- Technical Requirements
- Testing Requirements
- TR per FR Mapping
- Requirements Matrix
- Wordpairs
- Local Development
- Testing and Evidence
- Administration and Access Control
- Requirements Baseline v2.8
- Architecture Decision Record
- Architecture Design
- Architecture Patterns
- Content Moderation
- Deployment and Release Plan
- Acceptance Criteria Gap Analysis
- Acceptance Criteria Test Inventory
- Implementation Plan
- Phase 0 Execution
- Phase 0 Interface and Data Contracts
- Phase 1A Execution
- Phase 1 Execution
- Phase 2 Execution
- Phase 3 Execution
- Phase 4 Execution
- Phase 5 Execution
- Phase 6 Execution
- Optional Phase 6 Human Feedback
- Historical Chromium Crash Diagnosis
- Completed Coding Goal and Review Agreement
- Third Party Attributions
- Software Bill of Materials Contract
- Phone Installation and PWA
- Live Multiplayer Runtime and UI Integration
- UI Test Case Index
- UI Design Coverage
- UI Criterion Gaps
- UI Design Questions
- UI Test Persistence
- TEST-ACCESSIBLEGAMECONTROLS-044 UI Case
- TEST-ACLAUTHORIZATION-132 UI Case
- TEST-ADMINUI-136 UI Case
- TEST-AUTHORITATIVEANSWERHANDLING-045 UI Case
- TEST-BROWSEOPENLOBBIES-022 UI Case
- TEST-CATALOGVERSIONING-133 UI Case
- TEST-CATEGORYART-005 UI Case
- TEST-CATEGORYCHOICE-011 UI Case
- TEST-CATEGORYSUGGESTIONUNLOCK-019 UI Case
- TEST-CONFIGUREDCAPACITY-024 UI Case
- TEST-CONNECTIONRECOVERY-109 UI Case
- TEST-CONTENTVALIDATION-016 UI Case
- TEST-DEEPLINKJOINANDFULLROOM-026 UI Case
- TEST-FINALSTANDINGS-013 UI Case
- TEST-FIRSTCATEGORY-004 UI Case
- TEST-FREETIERQUOTAHANDLING-037 UI Case
- TEST-FULLROOMOBSERVER-027 UI Case
- TEST-GUESTPLAY-021 UI Case
- TEST-HINTPROGRESSION-009 UI Case
- TEST-HINTSCORING-007 UI Case
- TEST-HOLDOUTWARNINGANDREMOVAL-032 UI Case
- TEST-IDLELOBBYREADINESSPROMPT-033 UI Case
- TEST-INROUNDEMOJIREACTION-029 UI Case
- TEST-LANDINGPAGEPUBLICDATA-050 UI Case
- TEST-LIVESCORECARD-010 UI Case
- TEST-MODERATIONANDCATALOGBOUNDARY-047 UI Case
- TEST-NOHINTSOLVE-006 UI Case
- TEST-NOMINATIONELIGIBILITY-017 UI Case
- TEST-NOMINATIONMODERATION-114 UI Case
- TEST-NOMINATIONTHRESHOLDANDMODERATION-018 UI Case
- TEST-OBSERVERPERSPECTIVEANDPERMISSIONS-028 UI Case
- TEST-OIDCTOKENVALIDATION-046 UI Case
- TEST-OPENAIOIDCPROFILE-020 UI Case
- TEST-ORIENTATION-015 UI Case
- TEST-PLAYERLIMIT-002 UI Case
- TEST-PRECOUNTDOWNOBSERVERPROMOTION-030 UI Case
- TEST-PROFILEICON-003 UI Case
- TEST-PUBLICGAMELANDINGPAGE-043 UI Case
- TEST-PWAINSTALL-137 UI Case
- TEST-PWAPRIVACY-138 UI Case
- TEST-QUICKMATCH-023 UI Case
- TEST-READYCOUNTDOWNANDROSTERLOCK-031 UI Case
- TEST-ROOMINVITATIONS-025 UI Case
- TEST-ROOMJOINING-001 UI Case
- TEST-ROOMSYNC-139 UI Case
- TEST-ROUNDSUMMARY-012 UI Case
- TEST-SUGGESTIONREVIEW-115 UI Case
- TEST-TIMETIEBREAK-014 UI Case
- TEST-UNSOLVEDRESULT-008 UI Case
- UI Gap Decisions and Synchronization
- TEST-ACCESSIBILITYDETAILS-144 UI Case
- TEST-CANDIDATEHOLD-141 UI Case
- TEST-LOBBYMATCHING-117 UI Case
- TEST-NAVIGATIONDRAFTS-142 UI Case
- TEST-NOSOLVERFALLBACK-146 UI Case
- TEST-REQUESTFEEDBACK-143 UI Case
- TEST-RESPONSIVEMATRIX-145 UI Case
- TEST-REVIEWCHANGES-140 UI Case
- TEST-ROOMCODES-110 UI Case
- UI Gap Implementation Plan
- UI Gap Implementation and Evidence
- Contest Readiness
- Hostile Validation Evidence
- Category Artwork
- 10-Player Release Completion Plan
- Deadline Report and Token Accounting
- Deadline Report Supporting Evidence
- Deadline Timeline and Review Finding Analysis
- Stopped Wordpairs Release Handoff