Skip to content

Add manual public GraphQL schema reload#49

Open
Kzoeps wants to merge 9 commits into
mainfrom
feature/manual-schema-reload
Open

Add manual public GraphQL schema reload#49
Kzoeps wants to merge 9 commits into
mainfrom
feature/manual-schema-reload

Conversation

@Kzoeps

@Kzoeps Kzoeps commented May 22, 2026

Copy link
Copy Markdown
Member

Summary

  • add a reloadable public GraphQL schema manager with fallback behavior on failed reloads
  • validate admin lexicon uploads/registers before DB persistence
  • expose an admin reloadSchema mutation and wire it into public HTTP/WS GraphQL handlers
  • add the Lexicons UI action for manual public schema reload
  • document the plan/context and add Changie fragments

Validation

  • npm --prefix client run test
  • npm --prefix client run lint
  • npm --prefix client run build
  • go build -v ./...
  • DATABASE_URL=sqlite::memory: go test -v -race ./internal/graphql/... ./cmd/hyperindex
  • git diff --check

Manual Tap/client validation

  • ran Tap in Docker with:
    • TAP_SIGNAL_COLLECTION=app.certified.actor.profile
    • TAP_COLLECTION_FILTERS=app.certified.*,org.hypercerts.*
  • ran Hyperindex locally with TAP_ENABLED=true
  • ran the Next.js client locally
  • used agent-browser on /lexicons to upload app.certified.actor.profile, reload the schema, and confirm the UI success state
  • verified public GraphQL exposed appCertifiedActorProfile after reload
  • queried live Tap-ingested app.certified.actor.profile records successfully
  • checked collectionStats: 34 collections, 0 outside the configured Tap filters

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Reload schema" button on the Lexicons page to reload the public GraphQL schema after lexicon updates without requiring a backend restart.
    • Typed GraphQL collection fields now become available after schema reload instead of only after backend restarts.
  • Bug Fixes

    • Admin lexicon uploads and registration now validate documents before storage, preventing invalid lexicons from breaking schema reloads.
  • Documentation

    • Updated documentation to explain the manual schema reload workflow, including failure handling (previous schema remains active if reload fails).

Review Change Stack

@vercel

vercel Bot commented May 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperindex-atproto-client Ready Ready Preview, Comment May 22, 2026 4:55am
hyperindex-client Ready Ready Preview, Comment May 22, 2026 4:55am

Request Review

@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@Kzoeps has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 52 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 722f2718-e666-4984-81b4-1a9a201667b1

📥 Commits

Reviewing files that changed from the base of the PR and between 13f6502 and 7deca13.

📒 Files selected for processing (6)
  • AGENTS.md
  • README.md
  • cmd/hyperindex/main.go
  • internal/graphql/admin/resolvers.go
  • internal/graphql/admin/resolvers_lexicons_test.go
  • tests/api-smoke/README.md
📝 Walkthrough

Walkthrough

This PR implements a complete manual GraphQL schema reload system. Operators can now rebuild and atomically swap the public /graphql schema from filesystem and database lexicons via a new admin reloadSchema mutation without restarting the backend. The implementation introduces a reloadable schema manager with fallback semantics, strict validation of admin lexicon uploads/registrations before persistence, dynamic schema resolution in HTTP and WebSocket handlers, and a new Lexicons page admin UI for triggering reloads. The server returns HTTP 503 with actionable errors when no schema is available, preserves previous working schemas on reload failure, and includes comprehensive test coverage and documentation of the design.

Changes

Manual GraphQL Schema Reload

Layer / File(s) Summary
Public Schema Manager
internal/graphql/schema_manager.go, internal/graphql/schema_manager_test.go
PublicSchemaManager builds public GraphQL schema from filesystem and database lexicons with atomic snapshot publishing, fallback to previous schema on failure, and structured ReloadSchemaResult reporting including success, lexicon count, reload timestamp, and operator-facing error messages.
Admin Lexicon Validation
internal/graphql/admin/resolvers.go, internal/graphql/admin/resolvers_lexicons_test.go
Lexicon upload and registration now validate documents (parsing, ID checks) before persistence using ParseAndValidateLexiconDocument, rejecting malformed JSON and parser-invalid entries with detailed errors; upload validates entire ZIP before writing, register normalizes and validates requested NSIDs.
Admin Schema Reload Mutation
internal/graphql/admin/resolvers.go, internal/graphql/admin/schema.go, internal/graphql/admin/types.go, internal/graphql/admin/resolvers_reload_schema_test.go, internal/graphql/admin/handler_test.go
ReloadSchema resolver method invokes a schema reload callback wired during startup, returning GraphQL response with success/lexicon count/timestamp/error fields; mutation requires admin auth; expected failures (build/validation errors) return as data payload, unexpected errors return as GraphQL errors.
HTTP Handler Dynamic Schema
internal/graphql/handler.go, internal/graphql/handler_test.go
Handler refactored to use SchemaProvider interface for per-request schema resolution; if no schema is available, returns HTTP 503 with SCHEMA_UNAVAILABLE error and actionable extensions; test coverage added for missing-schema and schema-reload scenarios.
WebSocket Handler Dynamic Schema
internal/graphql/subscription/handler.go, internal/graphql/subscription/handler_test.go
WebSocket handler snapshots schema at subscribe time and keeps connections open when schema becomes unavailable (sending msgError for new subscribes); new operations on existing connections use latest schema after reload; test coverage for mutable schema providers and no-schema error payloads.
Main Wiring
cmd/hyperindex/main.go, cmd/hyperindex/main_test.go
setupGraphQL creates and initially reloads PublicSchemaManager, wires admin callback for operator-driven reload, and registers /graphql and /graphql/ws handlers via SchemaProvider; setupAdmin no longer loads disk lexicons directly; test validates callback wiring.
Frontend Client
client/src/lib/graphql/mutations.ts, client/src/lib/graphql/mutations.test.ts, client/src/lib/graphql/schema-reload.ts, client/src/lib/graphql/schema-reload.test.ts
RELOAD_SCHEMA GraphQL mutation document and TypeScript types (ReloadSchemaResult, ReloadSchemaResponse); formatReloadSchemaSuccess and formatReloadSchemaFailure generate operator-facing messages with correct lexicon count pluralization and fallback error text.
Frontend UI
client/src/app/lexicons/page.tsx, client/src/app/onboarding/page.tsx
Lexicons page adds admin-only "Public GraphQL schema" section with "Reload schema" button (disabled during mutation pending), loading label, and success/error messaging via formatted results; onboarding skip-step text updated to direct users to reload schema on Lexicons page instead of mentioning backend restart.
Documentation & Planning
docs/manual-schema-reload-plan.md, manual-schema-reload-context/gon-*.md, oracle/manual-schema-reload-plan-review.md, plans/manual-schema-reload-linear-*.json, README.md, client/README.md, .changes/unreleased/*.yaml, AGENTS.md, tests/api-smoke/README.md
Overall implementation plan with architecture, test checklist, and open questions; five detailed GON handoff docs (GON-60/61/62/63) with requirements, implementation steps, and success criteria; oracle review with correctness checks and recommendations; Linear issue tracking; updates to README and client README documenting reloadSchema mutation and workflow; Changie release notes for new operator feature and lexicon validation changes; minor AGENTS.md cleanup.

🎯 4 (Complex) | ⏱️ ~60 minutes

🐰 Schema reload hops in spring!
Operators now twist the knob—no restart needed today.
Atomic swaps and fallbacks play,
Strict lexicons guard the way.
The GraphQL garden blooms anew! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add manual public GraphQL schema reload' clearly summarizes the primary feature added in this changeset: enabling operators to manually reload the public GraphQL schema without restarting the backend.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/manual-schema-reload

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@internal/graphql/admin/resolvers.go`:
- Around line 631-642: The normalization currently trims overall NSID and checks
for empty segments but still allows segments that contain internal whitespace
(e.g., "app. test.foo"); update normalizeRequestedLexiconNSID to reject any
segment that contains internal whitespace characters by checking each part for
whitespace (e.g., compare part to strings.TrimSpace(part) or test for any \t\n\r
or space using strings.ContainsAny or a \s regexp) and return the same formatted
validation error when such whitespace is found; keep the function name
normalizeRequestedLexiconNSID and the existing error message.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3bc49a60-313c-4619-b8c9-ca65a81b01a1

📥 Commits

Reviewing files that changed from the base of the PR and between a3512a7 and 13f6502.

📒 Files selected for processing (34)
  • .changes/unreleased/add-manual-schema-reload-ui.yaml
  • .changes/unreleased/reject-invalid-admin-lexicons.yaml
  • AGENTS.md
  • README.md
  • client/README.md
  • client/src/app/lexicons/page.tsx
  • client/src/app/onboarding/page.tsx
  • client/src/lib/graphql/mutations.test.ts
  • client/src/lib/graphql/mutations.ts
  • client/src/lib/graphql/schema-reload.test.ts
  • client/src/lib/graphql/schema-reload.ts
  • cmd/hyperindex/main.go
  • cmd/hyperindex/main_test.go
  • docs/manual-schema-reload-plan.md
  • internal/graphql/admin/handler_test.go
  • internal/graphql/admin/resolvers.go
  • internal/graphql/admin/resolvers_lexicons_test.go
  • internal/graphql/admin/resolvers_reload_schema_test.go
  • internal/graphql/admin/schema.go
  • internal/graphql/admin/types.go
  • internal/graphql/handler.go
  • internal/graphql/handler_test.go
  • internal/graphql/schema_manager.go
  • internal/graphql/schema_manager_test.go
  • internal/graphql/subscription/handler.go
  • internal/graphql/subscription/handler_test.go
  • manual-schema-reload-context/gon-60-validation.md
  • manual-schema-reload-context/gon-61-admin-mutation.md
  • manual-schema-reload-context/gon-62-handler-provider.md
  • manual-schema-reload-context/gon-63-frontend-docs.md
  • oracle/manual-schema-reload-plan-review.md
  • plans/manual-schema-reload-linear-created.json
  • plans/manual-schema-reload-linear-issues.json
  • tests/api-smoke/README.md
💤 Files with no reviewable changes (1)
  • AGENTS.md

Comment thread internal/graphql/admin/resolvers.go

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13f6502a76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/graphql/admin/resolvers.go Outdated
…-reload

# Conflicts:
#	cmd/hyperindex/main.go
@Kzoeps

Kzoeps commented May 22, 2026

Copy link
Copy Markdown
Member Author

(reply generated by OpenAI Codex)

Checked the PR-level comments and review summaries:

  • Vercel preview comment is informational only.
  • CodeRabbit summary maps to the inline NSID whitespace finding; fixed in eb07733 and the thread is resolved.
  • Codex summary maps to the inline ZIP memory finding; fixed in eb07733 and the thread is resolved.
  • CodeRabbit merge-conflict note was addressed by merging origin/main in 7deca13; the PR is now mergeable.

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.

1 participant