Skip to content

test(db-parity): LadybugDB intermittently writes 51 fewer CONTAINS edges under runner load #1612

Closed

Description

@Shashankss1205

Database Parity Check is failing intermittently on main. Every metric matches across all four backends except REL_CONTAINS, where LadybugDB comes up short:

Metric          | KuzuDB | LadybugDB | FalkorDB | Neo4j | Match?
REL_CONTAINS    | 4600   | 4549      | 4600     | 4600  | NO

All node counts, REL_CALLS (664 total / 653 distinct / 11 duplicates), REL_INHERITS, REL_IMPORTS and REL_HAS_PARAMETER match exactly. It is only CONTAINS, and only Ladybug.

It is not a code regression

The same commit passes and fails depending on the run:

Run Ref LadybugDB CONTAINS Result
31731268289 0b616434 (branch) 4600 pass
31732292459 16828c78 (same code squashed to main) 4549 fail
same run, re-run 16828c78 4549 fail

ladybug resolves to 0.19.1 in both (released 2026-08-04, before either run), so it is not a dependency bump.

It correlates with runner load

The failing runs were markedly slower across every backend:

              KuzuDB   LadybugDB   FalkorDB   Neo4j
passing run   168.07      102.80      19.45   48.12
failing run   213.36      118.34      20.57   47.27

Kuzu +27%, Ladybug +15%, on an otherwise identical workload. That points at a load- or timing-dependent drop in the write path rather than anything deterministic about the graph.

Likely mechanism

Probably the same root cause as #1605: database_embedded_kuzu.py:743-757 deliberately forces a per-row fallback for relationship writes inside UNWIND to dodge a Kùzu planner bug. CONTAINS is by far the highest-volume relationship here (4600 vs 664 for the next biggest), so it is the most exposed to per-row write pressure — and LadybugDB is the Kùzu fork, sharing that path.

Losing 51 of 4600 edges (~1.1%) silently, with no error surfaced, is the part that matters most: the same drop would occur on user indexes and nothing would report it.

Suggested next steps

  1. Confirm whether the write path swallows an error — a per-row failure that is caught and logged at debug level would explain a silent partial write.
  2. Check whether the deficit is a stable 51 or varies with load; that distinguishes a truncation boundary from a race.
  3. Consider whether perf(kuzu): relationship batching is disabled, degrading every batched write to one query per row #1605's batching work removes this class of problem entirely.

Until then Database Parity Check will be red on main intermittently, which makes it easy to start ignoring — worth prioritising for that reason alone.

Activity

  1. github-actions commented on Aug 13, 2026

    @github-actions
    Contributor

    Hi! 👋 Join our CodeGraphContext Discord channel to collaborate: https://discord.gg/dR4QY32uYQ

  2. Shashankss1205 commented on Aug 13, 2026

    @Shashankss1205
    CollaboratorAuthor

    Update: Database Parity Check passed on main at 0883b8c0, the first green run since this was filed.

    Not claiming it's fixed — this is intermittent by nature and one green run proves little. But there's a plausible mechanism worth recording: #1617 landed in between, cutting write_inheritance_links from 144 label-pair queries to only the populated ones (−80% of that writer's calls, −35% of total queries on a single-language repo). If the deficit is load- or contention-related, as the timing correlation suggested, then materially reducing query pressure is exactly the kind of change that would make it less likely to reproduce — without actually fixing the underlying cause.

    Two reasons to keep this open:

    1. The suspected root cause — the per-row UNWIND fallback in database_embedded_kuzu.py:743-757 (perf(kuzu): relationship batching is disabled, degrading every batched write to one query per row #1605) — is untouched. perf(kuzu): skip empty label pairs in write_inheritance_links (-80% queries) #1617 removed an amplifier, not the mechanism.
    2. A silent partial write is the real problem. Whatever the trigger, LadybugDB dropped ~1% of edges and reported success. That would happen on user indexes too, and nothing would surface it.

    Related, from @rrodriguesNutrium on #1616: FalkorDB Lite runs its storage in a worker subprocess with timing-sensitive startup, and under CPU contention that worker can fail to come up while indexing still exits 0 with an empty graph. Same family of failure — an embedded backend under-writing silently rather than erroring. Whatever guard we add should probably cover both.

  3. moved this from Backlog tasks to In progress in CGC Progress Boardon Aug 18, 2026
  4. moved this from In progress to Done in CGC Progress Boardon Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions