Tested against: origin/main @ 8e84501a (post-v0.3.0 main head, 2026-07-07)
Severity: Medium — schema introspection returns a malformed column list;
any client that drives its column model from DESCRIBE sees a duplicate
primary-key column with conflicting null constraints.
Summary
DESCRIBE <collection> on a document_strict collection created with an
explicit id TEXT PRIMARY KEY now returns the id column twice —
once as id TEXT / nullable=false and once as
id TEXT PRIMARY KEY / nullable=true — plus a new __storage metadata
row. The two id rows contradict each other on nullability, and the
PRIMARY-KEY-marked one claiming nullable=true is wrong on its own.
Regression relative to 67c4572d, where DESCRIBE listed each column
once. Notably, the direct pg_attribute read for the same collection
now dedupes the explicit id against the synthetic primary key correctly
on this build — DESCRIBE appears to have missed the same dedup and
regressed in the opposite direction.
Repro
CREATE COLLECTION desc_repro (id TEXT PRIMARY KEY, label TEXT) WITH (engine='document_strict');
DESCRIBE desc_repro;
-- field | type | nullable
-- id | TEXT | false
-- id | TEXT PRIMARY KEY | true -- duplicate, contradictory nullability
-- label | TEXT | true
-- __storage | document_strict | false -- new internal row
-- (4 rows) -- expected: id once, label once
Expected
- One row per user column; the explicit
id and the synthetic primary
key resolve to a single entry (same dedup the pg_attribute path
already performs on this build).
- The primary-key column reports
nullable=false.
- Internal metadata rows, if exposed at all, stay consistently
__-prefixed (the __storage row follows that convention and is
easy to filter; the duplicate id is the defect).
Files (best-guess)
nodedb/src/control/planner/catalog_adapter.rs — the recent
explicit-id/synthetic-PK dedup landed here for catalog reads; DESCRIBE
resolves through a different path.
nodedb/src/server/shared/ddl/neutral/collection/describe.rs —
DESCRIBE handler; likely concatenates the declared column list with
the synthetic PK entry without deduping by field name.
Operational context
DESCRIBE is the introspection surface NodeDB itself recommends where
pg_catalog coverage is thin, so wire clients build their column models
from it. A duplicated PK column with conflicting null flags propagates
into client-side schema caches, dumps, and generated DDL — consumers
must now dedupe defensively and guess which nullability to trust.
Tested against:
origin/main @ 8e84501a(post-v0.3.0 main head, 2026-07-07)Severity: Medium — schema introspection returns a malformed column list;
any client that drives its column model from DESCRIBE sees a duplicate
primary-key column with conflicting null constraints.
Summary
DESCRIBE <collection>on adocument_strictcollection created with anexplicit
id TEXT PRIMARY KEYnow returns theidcolumn twice —once as
id TEXT / nullable=falseand once asid TEXT PRIMARY KEY / nullable=true— plus a new__storagemetadatarow. The two
idrows contradict each other on nullability, and thePRIMARY-KEY-marked one claiming
nullable=trueis wrong on its own.Regression relative to
67c4572d, where DESCRIBE listed each columnonce. Notably, the direct
pg_attributeread for the same collectionnow dedupes the explicit id against the synthetic primary key correctly
on this build — DESCRIBE appears to have missed the same dedup and
regressed in the opposite direction.
Repro
Expected
idand the synthetic primarykey resolve to a single entry (same dedup the
pg_attributepathalready performs on this build).
nullable=false.__-prefixed (the__storagerow follows that convention and iseasy to filter; the duplicate
idis the defect).Files (best-guess)
nodedb/src/control/planner/catalog_adapter.rs— the recentexplicit-id/synthetic-PK dedup landed here for catalog reads; DESCRIBE
resolves through a different path.
nodedb/src/server/shared/ddl/neutral/collection/describe.rs—DESCRIBE handler; likely concatenates the declared column list with
the synthetic PK entry without deduping by field name.
Operational context
DESCRIBE is the introspection surface NodeDB itself recommends where
pg_catalog coverage is thin, so wire clients build their column models
from it. A duplicated PK column with conflicting null flags propagates
into client-side schema caches, dumps, and generated DDL — consumers
must now dedupe defensively and guess which nullability to trust.