Referential-integrity audit of the workbench schema. No DDL change is needed: the four notebook children (cell, version, pinned result, share) already have foreign keys to sql_workbench_notebook. This adds a guardrail so a new reference cannot ship without one.
Stacked on #23 (branched from feature/schema-notebook-indexes), so the diff includes #23's index commit; merge #23 first.
PostgresIntegrationTest.testShippedDdlHasAForeignKeyForEveryReference: applies docs/ddl/postgres.sql on PostgreSQL (Testcontainers) and asserts every join and table possible-value reference between the workbench's tables has a foreign key, or an exemption with a reason. It also fails if an exempt reference gains a key, so the list stays accurate.
The only exemption is sql_workbench_execution.notebook_id, by design: the execution audit is append-only (AppendOnlyTableCustomizer) and outlives its notebook. CASCADE would delete audit rows. RESTRICT would block deleting any notebook that ever ran, because NotebookTableCustomizer.preDelete deletes cells, versions, pinned results and shares but not the audit. SET NULL would rewrite audit rows. The engine also records the client-supplied notebook id (SqlExecutionEngine.newAudit), which may name a notebook deleted meanwhile, and the audit insert must never fail.
The existing notebook FKs stay NO ACTION: the customizer deletes the children through QQQ (audits and locks apply) before it deletes the notebook.
Tests
Red: with fk_sql_workbench_cell_notebook removed from the DDL, the guardrail reports sql_workbench_cell.notebook_id. Green with the shipped DDL.
## Summary
Referential-integrity audit of the workbench schema. No DDL change is needed: the four notebook children (cell, version, pinned result, share) already have foreign keys to `sql_workbench_notebook`. This adds a guardrail so a new reference cannot ship without one.
**Stacked on #23** (branched from `feature/schema-notebook-indexes`), so the diff includes #23's index commit; merge #23 first.
- `PostgresIntegrationTest.testShippedDdlHasAForeignKeyForEveryReference`: applies `docs/ddl/postgres.sql` on PostgreSQL (Testcontainers) and asserts every join and table possible-value reference between the workbench's tables has a foreign key, or an exemption with a reason. It also fails if an exempt reference gains a key, so the list stays accurate.
- The only exemption is `sql_workbench_execution.notebook_id`, by design: the execution audit is append-only (`AppendOnlyTableCustomizer`) and outlives its notebook. CASCADE would delete audit rows. RESTRICT would block deleting any notebook that ever ran, because `NotebookTableCustomizer.preDelete` deletes cells, versions, pinned results and shares but not the audit. SET NULL would rewrite audit rows. The engine also records the client-supplied notebook id (`SqlExecutionEngine.newAudit`), which may name a notebook deleted meanwhile, and the audit insert must never fail.
- The existing notebook FKs stay NO ACTION: the customizer deletes the children through QQQ (audits and locks apply) before it deletes the notebook.
## Tests
- Red: with `fk_sql_workbench_cell_notebook` removed from the DDL, the guardrail reports `sql_workbench_cell.notebook_id`. Green with the shipped DDL.
- `./mvnw verify` green locally.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Referential-integrity audit of the workbench schema. No DDL change is needed: the four notebook children (cell, version, pinned result, share) already have foreign keys to
sql_workbench_notebook. This adds a guardrail so a new reference cannot ship without one.Stacked on #23 (branched from
feature/schema-notebook-indexes), so the diff includes #23's index commit; merge #23 first.PostgresIntegrationTest.testShippedDdlHasAForeignKeyForEveryReference: appliesdocs/ddl/postgres.sqlon PostgreSQL (Testcontainers) and asserts every join and table possible-value reference between the workbench's tables has a foreign key, or an exemption with a reason. It also fails if an exempt reference gains a key, so the list stays accurate.sql_workbench_execution.notebook_id, by design: the execution audit is append-only (AppendOnlyTableCustomizer) and outlives its notebook. CASCADE would delete audit rows. RESTRICT would block deleting any notebook that ever ran, becauseNotebookTableCustomizer.preDeletedeletes cells, versions, pinned results and shares but not the audit. SET NULL would rewrite audit rows. The engine also records the client-supplied notebook id (SqlExecutionEngine.newAudit), which may name a notebook deleted meanwhile, and the audit insert must never fail.Tests
fk_sql_workbench_cell_notebookremoved from the DDL, the guardrail reportssql_workbench_cell.notebook_id. Green with the shipped DDL../mvnw verifygreen locally.🤖 Generated with Claude Code