Blocked-by: #10676
Filed by the domain:engine execution seat (session_01RfyXxZ2WPjcjhuXpiQQc3y) as the consumer-side follow-up its own PR creates. Recording only — ⛔ no domain:* label; this lands in packages/services/service-datasource, which is not this seat's lane, and routing is triage's. The services seat asked for exactly this rather than an edit from the driver change.
What changes under it
PR #11124 (#10676 + #10998) aligns SqlDriver.introspectSchema() to the packages/spec introspection contract: columns carry primaryKey, and the retired isPrimary spelling is removed rather than emitted alongside.
ExternalDatasourceService's primaryKeyReader currently reads a three-signal union — col.primaryKey OR col.isPrimary OR table.primaryKeys.includes(col.name) — shipped by PR #11001 as a deliberate transitional belt while the two contracts disagreed. The maintainer ruling that ordered the driver alignment (2026-08-22, live session, 「同意所有」 item 9) permitted that belt for one release.
Once #11124 merges, the isPrimary arm has no in-tree producer. The belt is not broken — it keeps working precisely because it reads through a local cast ((col as { isPrimary?: unknown }).isPrimary) rather than through the interface, which is why removing the member does not touch it. That is good engineering and it is also what makes this easy to forget: nothing goes red, nothing complains, and a dead arm quietly becomes permanent.
Why the driver PR deliberately did not do it
The engine seat's dispatch authorised exactly one narrow cross-lane touch — updating external-introspection-seam.test.ts's producer-spelling assertion, which was built to redden on this flip — and ⛔ explicitly withheld authorisation to collapse the union read. Collapsing it is a judgement about how long the belt should outlive its producer, on a clock this lane does not own. The services seat's handoff note on #10676 says the same in the other direction: "Ping the services seat rather than editing it, or say so on this card and I will carve it." This card is that.
What the taker should check, not assume
Provenance
Blocked-by: #10676
Filed by the
domain:engineexecution seat (session_01RfyXxZ2WPjcjhuXpiQQc3y) as the consumer-side follow-up its own PR creates. Recording only — ⛔ nodomain:*label; this lands inpackages/services/service-datasource, which is not this seat's lane, and routing is triage's. The services seat asked for exactly this rather than an edit from the driver change.What changes under it
PR #11124 (#10676 + #10998) aligns
SqlDriver.introspectSchema()to thepackages/specintrospection contract: columns carryprimaryKey, and the retiredisPrimaryspelling is removed rather than emitted alongside.ExternalDatasourceService'sprimaryKeyReadercurrently reads a three-signal union —col.primaryKeyORcol.isPrimaryORtable.primaryKeys.includes(col.name)— shipped by PR #11001 as a deliberate transitional belt while the two contracts disagreed. The maintainer ruling that ordered the driver alignment (2026-08-22, live session, 「同意所有」 item 9) permitted that belt for one release.Once #11124 merges, the
isPrimaryarm has no in-tree producer. The belt is not broken — it keeps working precisely because it reads through a local cast ((col as { isPrimary?: unknown }).isPrimary) rather than through the interface, which is why removing the member does not touch it. That is good engineering and it is also what makes this easy to forget: nothing goes red, nothing complains, and a dead arm quietly becomes permanent.Why the driver PR deliberately did not do it
The engine seat's dispatch authorised exactly one narrow cross-lane touch — updating
external-introspection-seam.test.ts's producer-spelling assertion, which was built to redden on this flip — and ⛔ explicitly withheld authorisation to collapse the union read. Collapsing it is a judgement about how long the belt should outlive its producer, on a clock this lane does not own. The services seat's handoff note on #10676 says the same in the other direction: "Ping the services seat rather than editing it, or say so on this card and I will carve it." This card is that.What the taker should check, not assume
isPrimaryarm is the only dead one.table.primaryKeysremains a live, independent signal — the driver still emits it and it is the composite-key carrier (driver-sql: SQLite introspection reports only the FIRST column of a composite primary key (pk === 1vs SQLite's 1,2,3… numbering) #10997). ⛔ Do not collapse the union tocol.primaryKeyalone without establishing whatprimaryKeysis doing for callers.external-introspection-seam.test.tscurrently pins BOTH arms on purpose. Its updated comment says so: the union "no longer has an in-tree producer needing itsisPrimaryarm; collapsing it is this lane's call to make." Whichever way that call goes, that file is where it gets recorded.introspectSchema()emits the spec introspection contract —primaryKey,dialect,introspectedAt(#10676, #10998) #11124; whether any external driver implementation emits the old spelling is unmeasured here.defaultValue/indexesdivergences the driver kept deliberately (unknownrather thanstring;indexesomitted rather than emitted empty) are not part of this — they are documented divergences, not drift.Provenance
introspectSchema()returns only{ tables }— the specIntrospectedSchemacontract'sdialectand (required)introspectedAtare never emitted #10998 — the driver alignment (this card'sBlocked-by:fires when they close).introspectSchema()emits the spec introspection contract —primaryKey,dialect,introspectedAt(#10676, #10998) #11124 — the change that empties the arm.fields.<f>.primaryKeyfailstscagainstServiceObjectandObjectSchema.safeParse#11000 — unrelated despite the shared word, and still unruled:fields.<f>.primaryKeyauthorability in a rendered object definition is a different key in a different place.