External graph consolidation
Status: available in 0.14.0. Older servers require an upgrade before using these routes. Consolidation runs model inference in your application or worker; QilbeeDB coordinates durable jobs, exact source revisions and atomic publication. The database does not generate embeddings, call a model provider or accept its credentials. This contract does not establish a retrieval or agent-task quality gain.
Use consolidation to turn a bounded set of memories into typed assertions. Each accepted output depends on the entire declared context, including memories that are not its two endpoints. An extractor must declare every memory it uses. A database cannot discover context that the caller omitted, or independently certify a generated assertion as true.
Authorization and ownership#
All routes use POST, Authorization: Bearer <scoped-api-key>, JSON and
contract_version: 1. Company, project, agent, mission, visibility and private
subject are authorized before inspecting work. The authenticated subject owns
the job within that partition, including in a shared memory scope. Another subject
with access to the shared memories does not own that subject's jobs.
| Route | Capabilities | Purpose |
|---|---|---|
/api/v1/memory/consolidation/commands |
memory_read, memory_write |
Create, claim, renew, publish, fail, recover, cancel or reconcile usage |
/api/v1/memory/consolidation/inspect |
memory_read |
Retained current job, source diagnostic and current lease status |
/api/v1/memory/consolidation/revision |
memory_read |
Exact immutable job revision and its receipt |
/api/v1/memory/consolidation/query |
memory_read |
Bounded discovery of the caller's current jobs |
/api/v1/memory/consolidation/context |
memory_read, memory_write |
Exact source payloads for the current credential-bound lease |
worker_id is a caller label, not an authenticated identity. The server binds each
lease to the actual credential ID, an unpredictable fence and the current storage
incarnation. A second credential for the same subject can inspect the job but
cannot use the first credential's execution fence. Revoked credentials fail normal
authorization before a receipt can be replayed or a context read can succeed.
A consolidation job grants no additional source, review, tool-execution or company
administration authority. Its policy_ref identifies the caller's policy; it is
not an independently verified learning-policy approval. Published assertions use
the existing relation eligibility and review rules.
Create a job with a frozen manifest#
Send this envelope to /commands, replacing the fixture IDs and identities:
{
"contract_version": 1,
"scope": {
"project_id": "project",
"mission_id": null,
"agent_id": "agent",
"visibility": "private"
},
"idempotency_key": "consolidation-session-42",
"operation": {
"type": "create",
"spec": {
"sources": [
{"record_id": "018f0000-0000-4000-8000-000000000001", "revision": 2},
{"record_id": "018f0000-0000-4000-8000-000000000002", "revision": 1},
{"record_id": "018f0000-0000-4000-8000-000000000003", "revision": 4}
],
"objective": "Extract entity and evidence links supported by these memories.",
"policy_ref": "policy://entity-consolidation/v3",
"extractor": {
"origin": "model_inference",
"method": "entity-and-evidence-extraction",
"method_revision": "prompt-v3",
"evidence_ref": "trace://session-42/manifest",
"model": {
"provider": "example-provider",
"model": "example-model",
"revision": "example-pinned-revision"
}
},
"max_relations": 16,
"max_attempts": 3,
"lease_millis": 30000,
"max_attempt_millis": 300000
}
}
}
The manifest contains 2–16 distinct IDs with exact positive revisions. All must be current and transitively eligible in the same scope. Creation rejects an unavailable source or a context that cannot fit the bounded context response. The objective, policy reference, extractor and limits are immutable. Create a new job to change its context or extraction policy; do not reuse its idempotency key for new intent.
The result is contract_version and receipt. The receipt identifies job_id,
revision, action, original author and commit time, plus opaque job, command and
receipt digests. Store it durably. These integrity values are not signatures.
Claim and read the inputs#
Keep the command envelope and change operation to:
{
"type": "claim",
"job_id": "018f0000-0000-4000-8000-000000000010",
"expected_revision": 1,
"worker_id": "extractor-worker-7"
}
Use a distinct idempotency key for each intended operation. Competing claims with the same expected revision have at most one winner. A successful claim creates an attempt, a new fence and a server-clock expiry. It records unknown consumption before any external request, so a crash cannot silently become a zero-cost run.
Inspect the current job with contract_version, scope and job_id. The response
contains inspection.job, lease_active, recoverable, source_failure, the
evaluation time and dependency work. A replayed claim receipt is historical: it
does not prove that its lease is still active. Verify the current attempt before
invoking an external provider.
Request /context with the same envelope, job_id, the current job revision as
expected_revision, and the attempt's fence. It returns exact eligible source
records in manifest order, evaluated in one snapshot and clock. Another credential,
a stale revision, an expired fence or a previous storage incarnation is rejected.
A context response is not a freshness lease for the memories: publication checks
all sources again after inference finishes.
Long-running workers can issue renew with job_id, expected_revision and
fence. Renewal advances the job revision and extends the lease up to the fixed
max_attempt_millis deadline measured from the original claim. It keeps the same
attempt and fence. Renewal cannot revive an expired lease or extend a deadline
that would not advance. Use the current revision for the next operation.
Publish the complete output#
Send publish with the job ID, current expected revision, fence, an assertions
array, usage and an execution evidence_ref. Each assertion contains:
{
"source": {"record_id": "018f0000-0000-4000-8000-000000000001", "revision": 2},
"target": {"record_id": "018f0000-0000-4000-8000-000000000002", "revision": 1},
"kind": "same_entity",
"valid_from_millis": null,
"valid_until_millis": null,
"evidence_ref": "trace://session-42/assertion-1"
}
Both endpoints must match exact references in the manifest. The database copies the extractor's method and model identity and binds every other manifest source as additional relation evidence. A worker cannot omit inconvenient context from one output. Model origin remains a declared origin; an inferred causal claim does not become an observed causal fact.
A publication can contain zero assertions when extraction completed without a
supported relationship. It cannot exceed the job's max_relations. All assertions,
canonical relations, adjacency entries and completeness headers, sequential change
events, relation receipts, job state, immutable revision and command receipt commit
in one synchronous WAL batch. An invalid final assertion prevents the entire
publication. Shared endpoints accumulate their index counts and history positions
inside that same batch.
After publication, inspect job.output_receipts for exact relation identities.
published records a completed publication, not permanent permission to reuse
those relations. Updating, rejecting, deleting or expiring any declared source
can invalidate the outputs while the job and its publication history remain.
Record failure, uncertainty and cancellation#
usage is explicitly one of:
{"status": "unknown"}
{
"status": "reported",
"model_calls": 1,
"input_tokens": 420,
"output_tokens": 64,
"cost_microusd": null
}
Reported counts are caller observations, not provider billing verification. A missing or null cost is unknown. Use exact unsigned 64-bit integers; do not round large counts through a JavaScript floating-point value. Aggregate unknown consumption as unknown rather than substituting zero.
| Operation | Required additional fields | Durable result |
|---|---|---|
fail |
Current fence, usage, evidence_ref |
Close the attempt as failed; ready if attempts remain, otherwise exhausted |
recover_expired |
evidence_ref |
Close an expired or previous-incarnation attempt with unknown execution and consumption; permit a bounded retry if attempts remain |
cancel |
evidence_ref |
Make a ready/running job terminal; fence publication and retain unknown outcome/usage for an interrupted running attempt |
reconcile_usage |
Positive attempt_number, reported usage, evidence_ref |
Update a closed attempt's usage report; preserve older reports and uncertainty in immutable history |
All operations include job_id and expected_revision. Recovery can be driven
by application policy without a human confirmation step. It is explicit because
retrying an unknown external outcome may repeat a provider call or cost. Use the
provider's own idempotency or reconciliation mechanism where available. This
contract guarantees one accepted database publication per job; it does not provide
exactly-once external inference.
Restarting or restoring storage changes its incarnation, immediately fencing prior execution leases. Durable jobs and historical receipts survive. Canceling a job also fences publication, but does not prove that a remote provider or process stopped. An executor must separately implement cancellation if supported.
A usage reconciliation does not reopen a job, change its output or rewrite an unknown execution outcome as success. It records additional consumption evidence. Failures, corrections and unknown outcomes remain inspectable by revision.
Discovery, history and limits#
Query jobs with query.limit (1–100), query.scan_limit (1–1,000), optional
query.status and optional query.after. The cursor is a scanned UUID in the
current owner partition. Filtered jobs still advance it. Follow next_after until
null; an empty filtered page can still have a continuation. Pages are not a frozen
snapshot across requests. Rescan from the beginning to discover newly inserted or
changed work that sorts before a previous cursor.
Read /revision with contract_version, scope, job_id and a positive
revision. It returns that exact history.job and history.receipt. Never replace
current job inspection with an old acknowledgement when deciding whether to run.
| Boundary | Contract |
|---|---|
| HTTP request | 65,536 bytes on all five routes |
| Source manifest | 2–16 distinct current references in one scope |
| Context validation | One combined walk, depth 8 and 64 unique records; shared dependency cap 4,096 records / 16 MiB |
| Source payloads | 8 MiB of serialized canonical records; creation, claim, context and publication enforce this bound |
| Outputs | 0–16 assertions, constrained by the immutable job limit |
| Attempts | 1–32, constrained by the immutable job limit |
| Lease | 1–900 seconds; half-open expiry at the server's validation time |
| Attempt duration | At least one lease interval, at most 24 hours; renewal cannot exceed it |
| Current job / history | 512 KiB / 1 MiB per stored record |
| Job discovery | At most 1,000 scanned jobs and 4 MiB of canonical job bytes per request; integrity/history/output checks are additional |
Hard integrity, source, context or record-budget failures return an error, not a partially published result. Discovery provides a continuation when its count or canonical-byte budget stops a scan. These limits bound work; they are not a total process-memory or provider-spend guarantee.
All responses use Cache-Control: no-store. Handle 400 for invalid input or hard
bounds, 401 for missing/expired/revoked credentials, 403 for missing capabilities or
unauthorized scope, 404 for unavailable owner-scoped jobs/revisions, 409 for changed
revisions, inactive fences, stale sources or idempotency conflicts, 413 for request
size, 500 for encountered storage inconsistency and 503 for occupied admission
slots. A storage or network failure can have an unknown commit outcome: retry the
identical command and key before interpreting it as rejected.
This contract is an engineering prerequisite for the asynchronous consolidation examined in the graph research map. Qualification must separately establish transport, recovery and external worker behavior. Retrieval comparisons and downstream agent-task evaluation remain separate gates before promoting any extraction or ranking policy.
Run an external Python extractor#
The Python SDK exposes ConsolidationClient, ExternalConsolidationWorker,
SQLiteConsolidationJournal, ConsolidationInput, ConsolidationResult and
ConsolidationStopped. These classes use only the Python standard library.
Inference and provider credentials remain in the application's extractor.
from qilbeedb import (
ConsolidationClient,
ExternalConsolidationWorker,
SQLiteConsolidationJournal,
)
client = ConsolidationClient(
api_url,
api_key,
tenant_id=company_id,
subject_id=authenticated_worker_subject,
scope=authorized_scope,
)
worker = ExternalConsolidationWorker(
client,
SQLiteConsolidationJournal("/var/lib/my-agent/consolidation"),
worker_id="relationship-extractor",
)
result = worker.run_once(job_id, application_extractor)
Supply an application_extractor(input) callback returning a
ConsolidationResult(assertions, usage, evidence_ref, failed=False). Its input
contains the exact manifest, the selected source records, the attempt identifier
and a renew() function. Before the callback, the SDK validates the received
record contract: non-deleted payloads, source identifiers and revisions, author
and provenance fields, review disposition, expiration at the response's evaluation
time, and dependency-work bounds. An invalid context stops before the provider
intent is recorded or the extractor is invoked. These are response-contract
checks; they do not independently establish truth or traverse omitted ancestors.
The worker also requires the returned records to match the saved source manifest.
Job inspection and history also validate the immutable specification, complete
model identity for model inference, attempt numbering and fences, hard deadlines,
usage/outcome consistency, and output receipt ownership. Unknown enum values or
inconsistent lifecycle fields stop the SDK instead of authorizing extraction.
Receipt digests remain server-verified identifiers, not independent client proof.
Renew before the lease expires when necessary; the hard
attempt deadline still applies. A valid result with an empty assertion list
completes the job without inventing a relationship. Report unknown consumption as
{"status": "unknown"} when evidence is unavailable.
Use a private, persistent directory on a local POSIX filesystem. One journal holds an exclusive process lock across the provider call; it is not a distributed lock or an NFS coordination mechanism. The journal stores intent, output assertions and receipts, but does not store API keys or the source context payloads. Protect its contents as application evidence.
Before invoking the callback, the worker durably records that external execution
may begin. If the process dies or the callback fails afterward, a subsequent call
stops with provider_outcome_unknown; it does not automatically repeat inference.
Resolve the outcome using provider evidence and the explicit job lifecycle. Do
not delete a journal to make an uncertain attempt appear unstarted.
When output has already been durably prepared, retrying run_once sends the same
publication command and idempotency key. It does not regenerate the output. The
returned receipt describes the committed revision; result["inspection"] is a
separate current inspection. A network error while obtaining that inspection
still requires reconciliation; it does not undo a committed publication.
Supervise executions as a company administrator#
Company supervision requires credential_admin and remains restricted to the
administrator's company. It does not borrow a writer's credential or impersonate
the job owner. Discover authorized workspaces with
GET /api/v1/company/memory/workspaces, then select the returned workspace_id.
Workspace identifiers are opaque selectors; do not construct them from names.
Responses repeat the selected workspace. Verify the contract version, company,
workspace identifier, project, agent, mission, visibility and private subject
before using the result. Matching only a workspace identifier is insufficient
validation of a response. Directory continuations must advance through unique,
ordered workspace identifiers; retain the last confirmed page after an invalid
response rather than substituting an empty directory.
| Endpoint | Request fields in addition to contract_version: 1 |
Result |
|---|---|---|
POST /api/v1/company/memory/consolidation/query |
workspace_id, query |
Current jobs across owners in the selected workspace |
POST /api/v1/company/memory/consolidation/inspect |
workspace_id, owner_id, job_id |
Current job, source eligibility and lease state |
POST /api/v1/company/memory/consolidation/revision |
workspace_id, owner_id, job_id, revision |
Exact historical job and receipt |
POST /api/v1/company/memory/consolidation/cancel |
workspace_id, owner_id, job_id, expected_revision, idempotency_key, evidence_ref |
Cancellation receipt identifying the actual administrator |
A query uses limit, scan_limit, status and after, with the same count and
canonical-byte limits as owner discovery. Its continuation is an object containing
owner_id and job_id, not the owner endpoint's single UUID. Reuse the exact
returned object. An entry pairs owner_id with summary; use both the owner and
job when opening details. Pages are live observations, not a company snapshot.
A completed traversal of one workspace does not establish coverage of every
workspace or every change during traversal.
Within a workspace, entries follow the native index order: the UTF-8 bytes of
JSON-encoded owner_id, followed by the UUID bytes. This is not locale-aware
alphabetical order or JavaScript UTF-16 string order. A non-null continuation
identifies the last examined record, which may not match the status filter; it
must advance past the requested cursor and cannot precede the last returned
entry. An empty page can therefore still have a continuation.
Consumers should validate response identity, bounds, unique ordered entries and cursor progress before accepting a page. Preserve the last confirmed cursor and previously accepted entries when validation or transport fails, and retry that same page. Do not turn a malformed continuation into a completed traversal.
{
"contract_version": 1,
"workspace_id": "<workspace_id returned by discovery>",
"query": {
"limit": 25,
"scan_limit": 100,
"status": null,
"after": null
}
}
Cancellation is an explicit administrative decision with an audit reference. It fences database publication, but cannot guarantee that an external provider has stopped or has not charged for work. Inspect current state after cancellation and retain the receipt for audit.
When reading a historical revision, verify the job identifier, original owner, requested revision and receipt job/revision together. The receipt's commit time matches the historical job's modification time. The receipt actor can differ from the owner for administrative cancellation; do not rewrite that actor as the worker. A verified historical revision does not establish the current lease, source eligibility or execution status. Read current inspection separately.
Current inspection reports source_failure independently of execution status and
lease state. A ready or running job can have changed, deleted, expired, rejected
or unavailable evidence. Dependency limits or cycles can also prevent completing
the eligibility check. Display that condition to administrators; never infer
source eligibility from status or from the existence of an active lease.
A null source_failure describes only the inspection's evaluated_at_millis:
publication rechecks the source manifest and its dependencies.
If the cancellation response is lost, preserve the complete request and retry its original idempotency key. The console retains the command in browser local storage, bound to the signed-in account, company, workspace, owner and job. It contains the audit reason and request identity, not a session token. Closing a tab preserves that record; clearing site data, changing browser profiles or losing the device does not. Keep an independent receipt for operational audit.
The console coordinates submission across tabs using Web Locks and rereads the saved command under that lock. A confirmed command remains available for exact receipt verification from another tab. If browser storage or coordination is unavailable, cancellation is not sent. These browser mechanisms do not establish provider execution status or replace the server's revision and idempotency checks.
Do not infer rejection from a timeout or use a new key
merely because a response was lost. The server checks committed receipts before
revision conflicts under the mutation lock. An explicit HTTP 409
revision_conflict therefore rejects this command without applying it: refresh
current details and let the administrator decide whether to issue a new command.
An idempotency_conflict has different meaning and must not be treated as this
permission to replace an uncertain request.
Client revisions must retain their full unsigned 64-bit value. Browser clients must not round them through JavaScript's ordinary number arithmetic when they exceed its safe integer range. Historical receipts, current lease observations and external provider outcomes remain distinct pieces of evidence.