feat(data delete): reap ingestor bookkeeping rows with the table (RFC-0003 I6, backend#1209) - #424
Conversation
…e (RFC-0003 I6, backend#1209) Dropping a table stranded its run-journal rows (tracebloc_ingest_runs) and pseudonymization-salt row (tracebloc_ingest_meta). Under per-ingestion tables (data-ingestors#408) every dataset is its own table, so every delete would leak one husk row of each kind, unbounded. Teardown now DELETEs both best-effort after the DROP — separately per bookkeeping table (either may be absent on clusters that never ran a journal-aware ingestor), never failing a teardown whose DROP succeeded (TeardownResult.BookkeepingCleaned reports it). plan.Table has passed ValidateTableName, so it cannot escape the quoted literal. Benefits legacy label tables identically. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
bugbot run |
|
👋 Heads-up — Code review queue is at 48 / 30 Above the WIP limit. The team convention is to review existing PRs before opening new work. Open PRs currently in Code review (oldest first):
Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.) |
…string literal (Bugbot, High) The DELETEs embedded a single-quoted SQL literal inside a single-quoted sh -c string: the shell stripped the inner quotes, mysql saw an unquoted identifier, and the best-effort cleanup silently no-opped forever — exactly the leak this PR exists to stop. SQL now rides stdin (the runMySQLQuery pattern), sidestepping shell quoting entirely. The recording executor now captures stdin, and the test asserts the quoted literal arrives intact AND that no DELETE ever appears as a shell argument — pinning the whole bug class, not just this instance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot's finding (both threads — same bug) is correct and fixed in 98c0a56: the single-quoted SQL literal inside the single-quoted bugbot run |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 1260520. Configure here.
ReviewWell-scoped change (+136/-0), isolated to the teardown path with new regression tests. The core reasoning holds up:
Findings1. Observability gap — the leak this PR fixes could silently return (most important). 2. Cross-repo column assumption is only half-verified. 3. Reuse the existing 4. Minor — import grouping in 5. Minor — test-fake proliferation. RiskLow-to-medium as labeled — the DROP is unchanged and cleanup is strictly additive/best-effort. The real residual risk is silent: if the column assumption is wrong for the salt table, teardown keeps reporting success while the leak persists undetected. Fixing #1 (log on failure) is the highest-value change and makes #2 self-diagnosing in the field. |
…in the column contract (review) 1. Observability: TeardownResult gains BookkeepingErrs (per-table failure with mysql stderr folded in via runMySQLQuery); data delete prints a warning on incomplete cleanup and --output-json gains bookkeeping_cleaned — schema drift is now diagnosable in the field instead of collapsing into a silent false. 2. Column contract pinned in a comment against data-ingestors database.py: both bookkeeping tables key by table_name (tracebloc_ingest_runs indexed, tracebloc_ingest_meta PK). 3. The inline stdin exec is gone — DELETEs ride runMySQLQuery; its error prose neutralized to 'running mysql query' (the 'querying datasets' wording lives on only in list.go's own exec, whose test asserts it). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
All five addressed (latest commit):
Full suite green, lint clean, catalog +3 literals (the warn line, the neutral helper prose, the bugbot run |
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 61967b7. Configure here.
Re-review (commit
|
…e-clean too (Bugbot) + JSON cosmetic (review) data ingest --overwrite runs the identical teardown but discarded the result — a bookkeeping failure printed unconditional success, hiding on this path the exact schema-drift signal data delete now surfaces. The overwrite pre-clean warns the same way. Also: dry-run/declined emit bookkeeping_cleaned=false (nothing was attempted — a strict consumer must never read 'cleanup happened' out of a run that deleted nothing). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Both follow-ups in 79ee13c:
Suite green, lint clean, catalog +1 (the overwrite warn line). Thanks for the LGTM — nothing further queued on this branch. bugbot run |

Summary
The
tb data deletehalf of I6 (RFC-0003 D17, tracebloc/backend#1209): teardown now reaps the ingestor's bookkeeping rows together with the table.DROP TABLE, two best-effortDELETEs remove the table's rows fromtracebloc_ingest_runs(run journal) andtracebloc_ingest_meta(pseudonymization salts) — the rows that previously outlived every deleted dataset. Under per-ingestion tables (feat(ingestor): per-ingestion immutable tables ds_<uuid4().hex> behind PER_INGESTION_TABLES (backend#1205) data-ingestors#408) each dataset is its own table, so each delete would otherwise leak one husk row of each kind, unbounded; legacy label tables get the same cleanup for free.TeardownResult.BookkeepingCleanedrecords the outcome, no new user-facing output (no copy churn beyond the string catalog's one-line addition for the SQL literal).plan.Tablehas passedValidateTableName([A-Za-z_][A-Za-z0-9_]*), so it cannot escape the quoted literal —ds_<uuid4().hex>names pass that grammar natively.The rest of I6 (context)
Investigation results recorded on tracebloc/backend#1209: the backend needs no change — deletion is table-keyed and edge-driven, the hourly heartbeat enumerates tables via
information_schema(sods_tables are reported automatically), and the existing ingestor-id tombstone cascade already gives correct shared-handle semantics (dependents of a dropped table get tombstoned — no refcounting needed). The remaining half, the dead-run husk-table sweep, lands in the jobs-manager (client-runtime PR, next).Test plan
TestTeardown_CleansBookkeepingRows: both DELETEs observed against the right tables for ads_<hex>name; a failing DELETE leaveserr=nil,DroppedTable=true, PVC rm still runs,BookkeepingCleaned=false.go test ./...green;gofmt/go vetclean; string catalog regenerated (+1 line, the SQL literal).Epic: tracebloc/backend#1151 · Ticket: tracebloc/backend#1209 · Ingestor half: tracebloc/data-ingestors#408
🤖 Generated with Claude Code
Note
Medium Risk
Changes the destructive teardown path and in-cluster MySQL deletes, but cleanup is best-effort, table names are validated, and DROP/PVC removal behavior is unchanged on bookkeeping failure.
Overview
Dataset teardown now reaps ingestor bookkeeping after
DROP TABLE: best-effortDELETEs remove rows for the dataset fromtracebloc_ingest_runs(run journal) andtracebloc_ingest_meta(pseudonymization salts), keyed bytable_name. SQL is sent throughrunMySQLQueryon stdin so shell quoting cannot silently no-op the deletes.TeardownResultgainsBookkeepingCleanedandBookkeepingErrs; bookkeeping failures do not fail teardown once the drop succeeded.tracebloc data deleteand ingest--overwritepre-clean warn when cleanup is incomplete, and--output-jsonfor delete addsbookkeeping_cleaned(alwaysfalsefor dry-run/declined).Tests cover both DELETEs, stdin delivery, and that PVC removal still runs when bookkeeping fails; the shared MySQL exec error string is generalized to "running mysql query".
Reviewed by Cursor Bugbot for commit 79ee13c. Bugbot is set up for automated code reviews on this repo. Configure here.