What's wrong
The introspection model carries a foreign-key axis that is collected three different ways, at three fidelities, and read by nobody — and the Postgres collection is wrong.
Collected everywhere
schema-provider.ts:36-53 — 18 lines of Postgres SQL, a separate round trip
schema-provider.ts:70-82 — MySQL
schema-provider.ts:95-109 — ForeignKeyRow plus a third parameter
schema-provider.ts:139-154 — a second keyed pass
Carried through adapter.ts:36-42,46, glue/api/schemas.ts:300-306,310, mysql-adapter.ts:36-37 (a serial second round trip), postgres-adapter.ts:279-283, and sqlite-adapter.ts:49-52,157-180 — one PRAGMA foreign_key_list per table, doubling SQLite's N+1 introspection.
Read by nobody
grep -rn "\.foreignKeys" src/ returns three hits: the provider's own write (:152) and two of its own tests.
DatabaseExplorer.tsx, database-explorer-search.ts, table-query.ts, postgres-identifier-fixer.ts, StatusBar.tsx and the query hooks touch only tables, columns, tableName, tableSchema, databaseName, serverVersion. No referencedTable* reader repo-wide; no doc mentions an ERD feature.
The one planned schema consumer (todo.md:228, schema-aware autocomplete via CodeMirror sql({schema, dialect})) takes a table→columns map and has no FK input.
And the Postgres data is wrong
:49-50 joins constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name with no ordinal correlation to kcu and no schema qualification.
A composite FK (a,b) → (x,y) yields the 2×2 cross product — four rows with two wrong column pairings — and two same-named constraints in different schemas cross-join too.
MySQL and SQLite are correct, so the three dialects silently disagree about what the field means. Never noticed, because never rendered.
Proposed change
TableInfo = { tableName, tableSchema, columns }.
transformToSchemaInfo(databaseName, columnRows) becomes a single-pass group-by plus a sort, with no join key and no second collection.
This deletes a whole dimension declared three times, collected three ways at three fidelities, read zero times — and deletes the buggy join rather than obliging someone to fix data nobody wants.
Scope
Core: delete both FK queries, ForeignKeyRow, the third parameter, the :139-154 loop, and the two FK tests (:50-97, :227-256).
The deletion is only type-safe once TableInfo.foreignKeys goes, which also touches adapter.ts:36-42,46; mysql-adapter.ts:37,41; postgres-adapter.ts:281,286; sqlite-adapter.ts:49-52,56,157-180; schemas.ts:300-306,310; and foreignKeys: [] fixtures in 4 test files.
~23 occurrences across 11 files, all deletions, no behaviour change for any shipped feature.
Risks
The wire shape shrinks and SchemaInfoDto.foreignKeys is currently required, so main and renderer must ship together — they do, it is one bundle, and the schema response is not persisted (mutations.ts:130 removes the cached query; nothing writes it to SQLite).
The real risk is product intent: if an ERD or relations panel is on the roadmap this is a delete-and-redo. Worth one confirmation before executing.
Validation
The two deleted tests cover exactly the deleted code; sqlite-adapter.test.ts asserts the PRAGMA-derived FKs; databases.test.ts / api.test.ts exercise the response shape.
No new tests — the remaining transform tests (grouping, sorting, MySQL is_primary_key 1/0, column mapping) hold unchanged, which is itself good evidence the axis is separable.
Found in a codebase-wide simplification audit (F-S05-a). Confidence: high that the field is unused and the Postgres query wrong; medium only on the product question.
What's wrong
The introspection model carries a foreign-key axis that is collected three different ways, at three fidelities, and read by nobody — and the Postgres collection is wrong.
Collected everywhere
schema-provider.ts:36-53— 18 lines of Postgres SQL, a separate round tripschema-provider.ts:70-82— MySQLschema-provider.ts:95-109—ForeignKeyRowplus a third parameterschema-provider.ts:139-154— a second keyed passCarried through
adapter.ts:36-42,46,glue/api/schemas.ts:300-306,310,mysql-adapter.ts:36-37(a serial second round trip),postgres-adapter.ts:279-283, andsqlite-adapter.ts:49-52,157-180— onePRAGMA foreign_key_listper table, doubling SQLite's N+1 introspection.Read by nobody
grep -rn "\.foreignKeys" src/returns three hits: the provider's own write (:152) and two of its own tests.DatabaseExplorer.tsx,database-explorer-search.ts,table-query.ts,postgres-identifier-fixer.ts,StatusBar.tsxand the query hooks touch onlytables,columns,tableName,tableSchema,databaseName,serverVersion. NoreferencedTable*reader repo-wide; no doc mentions an ERD feature.The one planned schema consumer (
todo.md:228, schema-aware autocomplete via CodeMirrorsql({schema, dialect})) takes a table→columns map and has no FK input.And the Postgres data is wrong
:49-50joinsconstraint_column_usage ccu ON ccu.constraint_name = tc.constraint_namewith no ordinal correlation tokcuand no schema qualification.A composite FK
(a,b) → (x,y)yields the 2×2 cross product — four rows with two wrong column pairings — and two same-named constraints in different schemas cross-join too.MySQL and SQLite are correct, so the three dialects silently disagree about what the field means. Never noticed, because never rendered.
Proposed change
TableInfo = { tableName, tableSchema, columns }.transformToSchemaInfo(databaseName, columnRows)becomes a single-pass group-by plus a sort, with no join key and no second collection.This deletes a whole dimension declared three times, collected three ways at three fidelities, read zero times — and deletes the buggy join rather than obliging someone to fix data nobody wants.
Scope
Core: delete both FK queries,
ForeignKeyRow, the third parameter, the:139-154loop, and the two FK tests (:50-97,:227-256).The deletion is only type-safe once
TableInfo.foreignKeysgoes, which also touchesadapter.ts:36-42,46;mysql-adapter.ts:37,41;postgres-adapter.ts:281,286;sqlite-adapter.ts:49-52,56,157-180;schemas.ts:300-306,310; andforeignKeys: []fixtures in 4 test files.~23 occurrences across 11 files, all deletions, no behaviour change for any shipped feature.
Risks
The wire shape shrinks and
SchemaInfoDto.foreignKeysis currently required, so main and renderer must ship together — they do, it is one bundle, and the schema response is not persisted (mutations.ts:130removes the cached query; nothing writes it to SQLite).The real risk is product intent: if an ERD or relations panel is on the roadmap this is a delete-and-redo. Worth one confirmation before executing.
Validation
The two deleted tests cover exactly the deleted code;
sqlite-adapter.test.tsasserts the PRAGMA-derived FKs;databases.test.ts/api.test.tsexercise the response shape.No new tests — the remaining transform tests (grouping, sorting, MySQL
is_primary_key1/0, column mapping) hold unchanged, which is itself good evidence the axis is separable.Found in a codebase-wide simplification audit (F-S05-a). Confidence: high that the field is unused and the Postgres query wrong; medium only on the product question.