feat(backfill): discover dataset tables directly, not just the runs journal#395
Merged
Merged
Conversation
…ournal The runner enumerated the runs journal (list_registered_runs), which only has entries for datasets ingested by the post-journal ingestor. The pre-cutover backlog the backfill exists for was ingested BEFORE the journal, so it had no entry and was silently swept 0 (verified on dev: empty journal, ~170 real dataset tables untouched). Enumerate dataset tables directly instead: - Database.list_dataset_ingestor_ids() — scan information_schema for tables carrying the framework `ingestor_id` column (excluding the run journal + salt store), then read each table's distinct non-null ingestor_ids. Covers journalled AND pre-journal datasets (the journal is a strict subset). - backfill_datasets() defaults to this discovery. A table appended by several ingest runs has multiple ingestor_ids; metadata is table-level, so a table is backfilled once — the first id the backend resolves wins, siblings are skipped (a not_found/error id doesn't mark the table done, so another id can resolve it). Explicit ingestor_ids still supported. Tests: table discovery is the default; framework tables excluded; multi-id table backfilled once; sibling id retried after a not_found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 16e3d1e. Configure here.
Bundled with the table-discovery change so a single merge + v0.7.7 tag yields a deployable image carrying it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… the sweep (Bugbot #395) list_dataset_ingestor_ids scanned every dataset table with no per-table guard, so a single failing SELECT DISTINCT (scan timeout, table dropped mid-sweep, perms) aborted enumeration and skipped ALL tables. Wrap the per-table query in try/except: log the table name + exception TYPE only (never str(exc) — a driver message can embed cell values and feeds install logs) and continue. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
shujaatTracebloc
approved these changes
Jul 24, 2026
Collaborator
Functional review \u2014 passed\n\nBasis: the behavioural suites that ran on this PR at merge against real environments, not mocks:\n\n- \u2014 exercised against a real MySQL 8.0 service container, not a mock\n\nI could not reach the dev API (no dev credentials), so rather than rubber-stamp I used the strongest evidence available: these suites exercise the actual behaviour this change alters, on real infrastructure. Advancing \u2192 .\n\nIf the functional reviewer wants a manual pass on dev in addition, please move it back and say so. |
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.

Problem
The metadata-backfill runner (#393) enumerated the runs journal (
Database.list_registered_runs), which only has entries for datasets ingested by the post-journal ingestor. But the whole point of the backfill is the pre-cutover backlog — datasets ingested before the run journal existed, which therefore have no journal entry.Verified on the dev cluster:
tracebloc_ingest_runswas empty, yet the DB had ~170 real dataset tables (cats_dogs_train,cancer_classification_*,claims_*, …). The runner ran end-to-end and authenticated to the backend, but swept 0 datasets — exactly the tables it was meant to fix were invisible to it.Fix — discover dataset tables directly
Database.list_dataset_ingestor_ids()— scansinformation_schema.columnsfor every table carrying the frameworkingestor_idcolumn (excluding the run journal + salt store), then reads each table's distinct, non-nullingestor_ids. This covers journalled and pre-journal datasets — the journal is now a strict subset.backfill_datasets()defaults to this discovery (explicitingestor_idsstill supported). Because a table's metadata is table-level, a table appended by several ingest runs (multipleingestor_ids) is backfilled once — the first id the backend resolves wins; siblings are skipped. Anot_found/errorid does not mark the table done, so another id can still resolve the same table.Per-dataset guarding (one bad table can't abort the sweep) and the exit-code/log hygiene from #393 are unchanged.
Why table-scan is safe
ingestor_idcolumn are considered; the run journal (which also has the column) and the salt store are excluded by name.ingestor_ids are filtered out.not_found), not mis-backfilled.Tests
test_metadata_backfill_runner.py: discovery is the default (journal not called); a multi-id table is backfilled once; a sibling id is retried after anot_found.test_database.py:list_dataset_ingestor_idsscans information_schema, excludes framework tables, filters null/empty ids. Full runner+database+backfill suites green (82 passed).Rollout
Pairs with the client chart backfill hook (#380). No new endpoint or migration — a client-side enumeration change. After release, the hook's sweep will actually cover a client's pre-cutover tables.
🤖 Generated with Claude Code
Note
Medium Risk
Changes rollout enumeration and issues per-table
SELECT DISTINCTscans across all dataset tables (~170+ on dev), which can be slow or load MySQL during install hooks; backfill behavior is otherwise scoped and owner-checked via existing GET-by-ingestor_id.Overview
Fixes metadata backfill sweeps that processed zero datasets when the runs journal was empty but hundreds of legacy dataset tables still existed in MySQL.
Discovery: Adds
Database.list_dataset_ingestor_ids()— finds tables viainformation_schemathat have aningestor_idcolumn, skips framework tables (tracebloc_ingest_runs, salt store), and collects distinct non-null ids per table. Unreadable tables are logged and skipped so one failure does not stop the sweep.Runner:
backfill_datasets()with no explicitingestor_idsnow uses that discovery instead oflist_registered_runs(). Tables with multiple ingestor ids are backfilled once (sibling ids skipped after a definitive outcome);not_found/errordo not mark a table done so another id on the same table can still be tried.Bumps package version to 0.7.7; tests cover discovery, dedup, and sibling retry.
Reviewed by Cursor Bugbot for commit 1fe3b9c. Bugbot is set up for automated code reviews on this repo. Configure here.