WIP perf(graphile): harden tenant density without SQL rewrite - #1652
Draft
yyyyaaa wants to merge 3 commits into
Draft
WIP perf(graphile): harden tenant density without SQL rewrite#1652yyyyaaa wants to merge 3 commits into
yyyyaaa wants to merge 3 commits into
Conversation
This was referenced Aug 4, 2026
feat(server,graphile): opt-in blueprint pooling integration — GRAPHILE_BLUEPRINT_POOLING (5/6)
#1334
Closed
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.
Caution
This is a research draft, not a production-ready change. The measured data-plane design is promising, but production remains blocked on an atomic/versioned tenant security contract, WebSocket revocation, production policy proof, upstream Graphile review, and final workload qualification.
Summary
This draft supersedes the old Graphile scale stack #1330–#1335 and rebuilds its useful work on
origin/mainat2331ba016, while rejecting the part that made tenant isolation depend on runtime SQL rewriting and shared tenant blueprints.The objective is complete resident customer tenants per GiB of memory. A 1 GiB heap is one normalization point in the planned capacity matrix, not a product constraint.
Zhi's SQL-rewrite concern is sound: RLS filters rows after PostgreSQL resolves an object, so it cannot prove that a rewritten query reached the correct schema, function, sequence, index, metadata object, or privileged code path. Dan's plugin, BM25, and GUC concerns are also valid review requirements. This candidate addresses them by removing runtime rewrite/pooling entirely:
scoped-requiredfails closed and never silently falls back.Why this approach is better than the old stack
regclass-like valuesDISCARD ALL, prepared-cache clearing, and client destruction on reset failureSET LOCALrestoration is treated as expected PostgreSQL behavior, while every reused checkout starts from a sanitized state.This gives up the old stack's most aggressive same-blueprint sharing claim. That is deliberate: density is only useful when tenant isolation remains at least as strong as today's exact physical boundary.
Progress
origin/mainsnapshot2331ba016.503codes, and observability.TenantSecurityContractV1with one atomic, monotonic revision across routing and all security metadata.authRequiredan authoritative routed API contract.mainadvanced tod66ae8e18after this branch was pushed, and GitHub currently reports merge conflicts. Per this draft's scope, parity is deferred rather than hidden.What this draft includes
GraphileBuildContractV1identities over the complete tenant/API execution contract, never hostname alone.DISCARD ALL, node-postgres/Graphile prepared-statement bookkeeping reset, and client destruction on failure.BYPASSRLS,CREATEROLE, ownership, schemaCREATE, unsafe inheritance/SET ROLE, unsafeSECURITY DEFINER, and cross-schema dependency capabilities.Detailed notes live in:
research/graphile-density/REPORT.mdresearch/graphile-density/SECURITY-AUDIT.mdresearch/graphile-density/PLUGIN-SQL-AUDIT.mdresearch/graphile-density/UPSTREAM-REVIEW.mdConfirmed performance evidence
The clean benchmark used a production-shaped catalog with 62,298
pg_classrows, 346,369 attributes, 8,496 procedures, 23,709 types, and 4,036 namespaces. Each arm ran in three fresh Node processes with a 4 GiB V8 heap and warmed 100 distinct Grafast operations plus three exact replay passes.Both arms emitted the same 17,976-byte GraphQL SDL with SHA-256
5fb82f96153815b23820a9ccf10322a20c864e49605ef5781cd33422b3b31020, and the recorded operations had zero errors, mismatches, or cross-tenant tokens.The raw clean-run summaries remain local/gitignored at:
research/graphile-density/artifacts/production-shaped-20260801-v6-clean/stock-release-destroy-clean-h4096-r3/summary.jsonresearch/graphile-density/artifacts/production-shaped-20260801-v6-clean/scoped-dependency-release-destroy-clean-h4096-r3/summary.jsonThese numbers measure one dedicated Graphile surface, not complete customers per GiB. They predate the final security-hardening pass, so they do not establish final-code throughput, p99, cache capacity, or production readiness. Security checks must not be removed to recover benchmark performance.
Confirmed isolation evidence and its limit
Before the final
mainrefresh, a disposable PostgreSQL 18 A/B/C fixture used three distinctLOGIN NOINHERITruntime roles, forced-RLS tenant tables, exact physical pools, scoped-required introspection, BM25/vector/PostGIS/ltree, and realtime-resident instances. It passed 56/56 hostile checks in 3.9 seconds withcrossTenantTokens: 0.The checks covered generated and plugin SQL, cross-schema identifiers, metadata, functions, sequences, search extensions, owner/BYPASS rejection, poisoned GUCs, rollback/savepoints, same-backend prepared-statement reuse, schema drift, cache invalidation, concurrent cold builds, realtime instances, and alternating connection reuse. Separate live PostgreSQL sanitizer and runtime-role suites passed 2/2 each.
The generated hostile-run artifact remains local/gitignored at
research/graphile-density/complete-tenant-fixture/generated/hostile-validation.json. This evidence validates the fixture and exact physical data-plane mechanism, but it does not prove every deployed schema, policy, role grant, dependency object, provider integration, or control-plane transition. The hostile run must be repeated after the rebase and after the versioned security contract lands.Why this is not production-ready
Production is currently a no-go. The unresolved work is part of the security contract, not cleanup.
Routing and security metadata do not share one atomic revision. Routing, RLS, auth, feature, CORS, public-key, and WebAuthn data are loaded independently. A domain handover or revocation can leave an in-flight HTTP request using a captured old authorization snapshot. Exact identities confine it to the captured physical tenant, but stale authorization is still incorrect.
Long-lived transports do not yet revalidate against authoritative current state. A WebSocket operation compares against the connection's captured route/generation. A handover or revocation can remain effective only after the socket closes or its generation retires. The new revision must drive admission, cache retirement, active subscription termination, and every operation check.
The production database policy manifest is unproven. The fixture proves the mechanism, while production still needs verification of every runtime/request role, exposed/dependency object, shared-row RLS policy, and intended
FORCE ROW LEVEL SECURITYrule.Authentication requirements are not yet authoritative per API.
strictAuth=falsedeliberately supports public APIs and permits a missing RLS module. APIs that require authentication need a routedauthRequiredcontract so missing configuration fails closed.Scoped introspection depends on local source patches. It must remain off by default until Graphile maintainers review the isolated API and the patches are replaced with supported upstream behavior.
Operational trust boundaries still need deployment proof. The internal routing credential must be stripped at public ingress and accepted only over authenticated encrypted service hops.
X-Meta-Schemais a disabled-by-default cross-tenant administrative capability and requires a separate private ingress if enabled. Runtime credential resolution and explicitly admitted plugins remain trusted code.Release qualification is incomplete. Full parity with current
main, external LLM/MinIO paths, multipart byte roundtrips, repeated complete-customer density runs, mixed workload latency/error gates, and the two-hour maximum-density soak remain open. The 6.55 MiB result is not yet a safe governor capacity setting.The old PR stack is deprecated
This draft is the only continuation path. #1330–#1335 are retained as historical provenance and should not be merged independently.
The old approximately 14.7 MiB retained-heap, 417 ms cold-build, 87x reduction, and same-blueprint density claims came from the rejected rewrite/pooling system. They are historical context, not current evidence. The current dedicated-instance evidence is 6.55 MiB and 130.34 ms for one production-shaped surface; complete-customer density is still pending.
Validation status
Post-rebase focused checks completed for this draft:
git diff --checkare clean.The full root build and broader package/security suites passed on the pre-rebase tip, but they are deliberately left unchecked above until rerun for current-main parity. The MinIO integration suite could not connect to a local MinIO service; live provider/storage qualification remains an explicit gate rather than a skipped success.
Scope
This PR changes only
constructive. It contains noconstructive-dbchanges, deployment, production enablement, SQL rewrite, or tenant blueprint pooling. Stock introspection remains the default, and no upstream maintainer has been contacted.Suggested review order: security audit and routing/runtime boundary first, Graphile source patches second, plugin trust/raw SQL paths third, then cache governor and benchmark harness.