Repository navigation
v1.4.6
Release Notes v1.4.6
Released: 2026-10-07
This release makes the cold graph page proof cheap enough for large graphs: snapshot and entity lookups now run in index-served clumps instead of handing SurrealDB 3.2 thousand-element IN lists, cutting a 12K-entity proof from 79s to 25s. Alongside it, the lifecycle acceptance gate gains end-to-end proof that a committed write survives response loss and a real daemon restart.
Highlights
Cold graph page proves in 25s instead of 79s
SurrealDB 3.2 serves an IN list from an index only up to 32 values; past that it scans the table and tests every row against the whole list, so cost grew as rows times ids. The graph page's cold proof handed it thousands of ids per statement, which pushed a 12K-entity graph past a team server's gateway timeout. The same graph now proves in 25s with an identical set of entities and edges.
Index-served lookup clumps
operational_relationships.org_lookup_clumps() builds [$org, ids] pairs via array::clump(array::distinct($ids), 32), so each lookup stays on the index. Duplicates are removed first: an id split across two clumps would return its row twice where a single IN returns it once. Each clump carries its organization in the closure argument, because a closure body that references any other binding silently evaluates to nothing on at least one engine. Rows are sorted in an outer select, since an ORDER BY beside the IN turns the plan into a full ordered index walk.
Snapshots without vectors for read-only comparisons
_snapshot() takes a new include_embeddings flag. Callers that only compare rows (graph_read_availability, graph_view_availability) pass include_embeddings=False and get rows back without embedding, name_embedding or fact_embedding, and without the write fingerprint, which covers stored vectors and cannot be computed without them. Vectors are storage, not evidence, and neither side of the comparison reads them now.
Overlapping relationship batches on pooled clients
New _each_batch() helper in graph_read_availability.py runs batch reads concurrently with asyncio.gather when the client pool has more than one slot, and sequentially otherwise. The single-slot path is deliberate: an embedded store only queues overlapping reads, and a queued waiter binds the pool's queue to the current event loop, which a later loop reusing the same client cannot wait on.
Lifecycle recovery proven across native restarts
Twenty complete capture, revise, delete, restore and recall chains now run over native storage in apps/e2e/tests/cli/test_memory_lifecycle_recovery.py: two scopes (private, project) across four injection phases (capture x4, revise x2, delete x2, restore x2). Each case loses the acknowledgement after the write commits, restarts the daemon, flushes the retained pending write with its original idempotency key, and compares full receipts, with recall as the post-recovery verification step rather than an injection point.
Graph Performance
operational_relationships.py:_SNAPSHOTis now generated by_snapshot_lookups(vectors=True), with a matching_SNAPSHOT_WITHOUT_VECTORSvariant. All four lookups (entity,memory_derivations,source_states,relates_to) go through clumps.graph_entity_search.py: entityget_manyreplaces per-uuid point lookups witharray::clump($uuids, 32)over the unique index, costing a fraction of one lookup per uuid.graph_read_availability.py: relationship endpoint reads use the clumped query and run concurrently per batch; initial capture and recapture both skip vectors.graph_view_availability.py:available_graph_viewtakes its snapshot withinclude_embeddings=False.
Correctness Evidence
test_operational_snapshot_plans.pykeeps a_SINGLE_IN_SNAPSHOToracle, the exact statement shape the clumped lookups replaced, and asserts the clumped snapshot returns the sametargets,associations,states,relationshipsandfingerprintover 70 entities and 40 edges, including foreign-group decoys, missing ids, and a duplicate straddling a clump boundary.- A live-server test (
SIBYL_LIVE_SURREAL_TESTS=1withSIBYL_SURREAL_URL) runsEXPLAINon each clumped lookup and asserts the expected index (idx_entity_uuid,memory_derivation_target,source_state_identity,idx_relates_uuid) appears andTableScandoes not. - Shape tests assert
_LOOKUP_CLUMP <= 32, that everyINbinds$lookup[1], and that no closure body names$orgor contains anORDER BY.
Lifecycle Testing
apps/e2e/tests/cli/lifecycle_runtime.py:LifecycleRuntimeowns one persistent native store, asibyld serve --embeddeddaemon, a recording HTTP proxy, and an isolated CLIHOME;OwnedCLIruns each CLI subprocess with its own environment and queue. Startup is verified against a per-runSIBYL_GIT_COMMITnonce in/health, and shutdown asserts the proxy thread is reaped.- Loss injection is narrow: the proxy drops an acknowledgement only for a POST to the targeted path that returned success with a JSON
mutation_receiptwhoseappliedis true and whoseidempotency_keymatches the request header. apps/e2e/tests/cli/test_lifecycle_proxy.py: seven forwarding cases (plain-text error, empty 204, ordinary JSON, error-with-receipt, unapplied receipt, mismatched key, malformed receipt) confirm the proxy preserves status, body and content type without arming the fault. A genuine upstream disconnect recordsRemoteProtocolErrorand returns an explicit502, keeping transport failure distinct from deliberate loss.- Embeddings are disabled through missing provider credentials, so the acceptance campaign requires no paid inference.
Release and Deployment Artifacts
VERSION,apps/api/pyproject.tomlandapps/cli/pyproject.tomlmove to 1.4.6.charts/sibyl/Chart.yamlbumps bothversionandappVersionto 1.4.6.charts/surrealdb/Chart.yamlbumpsversionto 1.4.6 only; itsappVersionstays"3.2.4", which tracks the SurrealDB release it wraps.docker-compose.quickstart.ymldefaultssibyl-api,sibyl-workerandsibyl-webimages to1.4.6;infra/ansible/roles/sibyl/defaults/main.ymlsetssibyl_version: "1.4.6".- Deployment and installation docs (
docs/cli/docker.md,docs/deployment/ansible.md,docs/deployment/helm-chart.md,docs/deployment/kubernetes.md,docs/deployment/monitoring.md,docs/guide/installation.md) reference the new tag.
Compatibility
No breaking changes. For the full _SNAPSHOT statement, rows, their order and the operational write fingerprint are unchanged from the single-IN shape, as asserted against the oracle statement in test_operational_snapshot_plans.py. The no-vector variant deliberately omits the fingerprint, so that equivalence applies only to callers that read with embeddings.
Upgrade Notes
- Update image tags to
1.4.6, or setSIBYL_IMAGE_TAG/sibyl_versionexplicitly if you pin. - Helm users:
sibyl-surrealdbchartversionmoves to 1.4.6 while itsappVersionstays3.2.4. No SurrealDB engine change is implied. - No schema migration and no index changes are required; the gains come from query shape alone.
- To exercise the live planner assertions locally, run the core test suite with
SIBYL_LIVE_SURREAL_TESTS=1andSIBYL_SURREAL_URLpointed at a SurrealDB server (the embedded engine plansINlists differently and those cases skip). - The lifecycle acceptance suite needs the owned backend environment prepared with
moon run api:sync; setSIBYL_LIFECYCLE_RECEIPT_DIRto keep per-case receipt JSON for triage.
Install
Local server
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.6Remote CLI
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --remote --version 1.4.6
sibyl init --remote https://sibyl.example.com
sibyl auth loginHomebrew
brew install hyperb1iss/tap/sibyl
sibyl upArch Linux (AUR)
paru -S sibyl
sibyl upHeadless server
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.6 --no-openKubernetes (Helm)
helm repo add sibyl https://raw.githubusercontent.com/hyperb1iss/sibyl/gh-pages
helm repo update sibyl
helm upgrade --install sibyl sibyl/sibyl --version 1.4.6Artifacts
This release includes Python wheels and sdists, the generated
Homebrew formula, the generated AUR PKGBUILD, Helm charts, Docker
SBOMs, aggregate dual-registry cosign receipts, and a SHA256 checksum
manifest.