Privacy-safe external graph ingestion¶
GraphQL APIs, Neo4j/openCypher, Apache AGE, LadybugDB, and remote
epistemic-graph instances enter through one governed external-source lifecycle.
Durable AgentConfig contains neutral aliases, bounded policy values, and
secret references only. Endpoints, credentials, queries, variables, TLS
material, and customized source ontologies remain outside the repository.
Governed ingestion lifecycle
A reference-only AgentConfig flows through a runtime reference resolver,
bounded read-only schema discovery, an opaque mapping proposal, a
digest-bound approval, and ChangeEnvelope ingestion into the
epistemic-graph authority. Schema drift detected at the discovery step
feeds back into a new mapping proposal.
Reference-only declaration¶
EXTERNAL_GRAPH_CONNECTORS is a list of typed
ExternalGraphConnectorConfig objects. A GraphQL document source looks like:
{
"EXTERNAL_GRAPH_CONNECTORS": [
{
"name": "external-catalog",
"source_alias": "domain-knowledge",
"backend": "graphql",
"connection_profile_ref": "vault://external/catalog-connection",
"mapping_policy_ref": "vault://external/catalog-mapping",
"auth_profile_ref": "vault://external/catalog-auth",
"tls_profile_ref": "vault://external/catalog-tls",
"variables_ref": "vault://external/catalog-variables",
"ingest_operation": "entity_document",
"discovery_max_types": 200,
"discovery_max_depth": 6,
"ingest_max_records": 1000,
"require_approval": true,
"schema_drift_policy": "fail_closed"
}
]
}
The connection reference resolves only the transport location. Authentication,
TLS, mapping/query policy, and operation variables use separate references so a
single combined profile cannot accidentally cross trust boundaries. Public MCP
and REST actions accept the connection alias, bounded options, an approved
operation alias, and an optional variables_ref; they reject inline endpoints,
headers, credentials, queries, mappings, variables, and certificate paths.
Discovery and approval¶
The lifecycle is the same for GraphQL and property graphs:
discover_connection_schemaperforms a bounded read-only inspection.propose_connection_mappingcompares the discovered schema with the native ontology and stores only privacy-safe schema and mapping digests.approve_connection_mappingbinds operator approval to the exact schema and policy digests.external_graph_doctorreports redacted discovery, approval, schema-drift, and runtime mapping-policy-drift readiness.ingest_connectionrediscovers the source, fails closed on drift, and applies approved records through nativeChangeEnvelopetransactions.
Discovery never approves its own output. A partial discovery cannot produce an approved profile unless the connector's bounded-probe policy explicitly defines that completeness contract. Schema or policy changes require a new proposal and approval.
GraphQL transport rules¶
Connection, mapping-policy, and auth references must resolve to the exact
current formats graphql-connection/v1, graphql-document-policy/v1, and
graphql-auth/v1, respectively. Missing or unknown versions fail closed in
doctor and at runtime. Connector TLS references are parsed through the shared
TLS-profile resolver; a nonempty but malformed trust document is not ready.
GraphQL documents are parsed with the GraphQL AST. Exactly one query operation is allowed; mutations, subscriptions, unsupported definitions, unapproved introspection, excessive token/depth shapes, and unbounded discovery probes are rejected. Keyword matching is only defense in depth, never the authority.
The production transport reads bounded bytes before JSON decoding. Redirect, response, page, entity, section, document, character, and timeout budgets are enforced across the whole operation. Injected transports must return the same bounded raw-byte contract and are restricted to isolated tests. Upstream error messages and response rows are never copied into public errors or traces.
Mapping policies may define multiple approved operations, including domain- or
lifecycle-shaped documents, without compiling a customer's schema into Agent
Utilities. Variables are selected from variables_ref by operation alias.
Optional-field fallbacks and partial-error handling must be explicit policy;
they are not inferred from one environment.
Property-graph transport rules¶
Neo4j/openCypher over Bolt, Apache AGE/openCypher, LadybugDB/Kuzu-compatible, and remote epistemic-graph adapters discover labels/types, properties, relationships, and supported capabilities through backend-specific read-only adapters. Generated mapping proposals select privacy-safe property allowlists and ontology candidates.
The direct property-graph path cannot read a source until the fixed
external_graph native activation contract passes the signed
connector-manifest gate. The bundle pins the actual importer module and contains
its deterministic critical local dependency closure; a governance, envelope,
privacy, configuration, or registry dependency change therefore invalidates the
fingerprint too. It contains no source-specific profile or ontology. Doctor
exposes only the gate's ready/not ready state; it never returns the manifest
location or verification details.
Every import query is structurally validated as a single bounded read. The adapter enforces driver-side or streaming row caps and stops as soon as the cap is exceeded. Mutating clauses, procedures outside the discovery allowlist, mirror-role writes, and responses that ignore the bound are rejected. Edges are accepted only when both endpoints passed the node privacy gate.
AgentConfig owns the bounded property-graph sync policy: page size, maximum
pages, per-row and cumulative bytes, nesting depth, collection size,
auto/cdc/snapshot mode, deletion reconciliation, and explicit empty snapshot
authority. That policy is part of the approved mapping digest. A backend with a
snapshot token may page inside one repeatable source snapshot. A tokenless backend
uses one max_records + 1 sentinel read per query and never composes independent
offset reads. Complete source-native CDC is used when the adapter exposes it;
otherwise deterministic snapshot comparison emits tombstones. Missing mapped
identities, changed snapshot tokens, structural-budget violations, incomplete or
failed reads, and unexpectedly empty results never delete records or advance an
authoritative source snapshot.
The approved runtime mapping-policy document is canonically hashed without persisting its contents. Doctor and ingestion resolve and re-hash the same ref; any change fails closed until a new proposal is approved. Each property-graph upsert also receives an HMAC material version covering its sanitized properties and outgoing links. Native idempotency therefore skips unchanged records but does not lose an edge-only delta. GraphQL uses its native version-map checkpoint to emit only changed envelopes, and the engine advances that checkpoint only after the whole batch succeeds.
Identity, ACL, and trace privacy¶
The runtime profile supplies a private HMAC key used to derive stable opaque source identities. Raw upstream IDs, personal names, account identifiers, endpoints, database names, query text, host names, and local filesystem paths do not enter graph properties, checkpoints, reports, or Langfuse metadata.
PersistencePrivacyGuard sanitizes approved values before materialization.
Missing access evidence becomes ExternalAccess.quarantined(); no profile can
turn an unknown ACL into public access. Each envelope carries tenant,
classification, retention, legal hold, mapping version, provenance digest, and
engine-owned cursor evidence. The engine commits graph rows, policy, lineage,
cursor, and outbox effects atomically.
TLS verification is mandatory. A source may use system trust or a referenced
named TLS profile containing private CA, mTLS, and proxy policy. Certificate
material is resolved into a private runtime location and is never persisted in
AgentConfig or documentation.