Skip to content

service-datasource still reads the retired turso config.timeout, so a datasource authored with the canonical timeoutMs is dropped at the seam that builds the driver config #16023

Description

@os-sales

Surfaced while implementing #15682 (stack card 6/6 of #14478). Not in that card's scope — it lands in packages/services/service-datasource, and the card owns the gate's population plus @objectstack/driver-turso. Filed bare for triage.

What was measured

packages/services/service-datasource/src/turso-driver-config.ts:170:

  timeout: ({ config }) => (typeof config.timeout === 'number' ? config.timeout : undefined),

This is the reader table that turns a DatasourceConnectionSpec into a libSQL driver config — the ONE place both loaders go through since #7314. It reads the authored key config.timeout.

#15680 (stack card 5/6) renamed that authored key: packages/spec/src/data/driver/turso.zod.ts now declares timeoutMs, and timeout is a retiredKey() tombstone. So the spelling this reader consults is the one the authoring contract now refuses, and the canonical spelling is the one it does not read.

Why nothing catches it

Three things, each of which would normally have:

  1. No typecheck. TursoConfigSource.config is declared as a bare string-keyed bag (Record, values unknown) at :94, "narrowed to a bag so each reader can type-test its own key" — so config.timeout compiles whatever the schema says.
  2. The test authors the retired spelling. src/__tests__/turso-driver-config.test.ts passes config: { … timeout: 9000 } at :47 and timeout: 0 at :100, and asserts it flows through. It is green, and it stays green for exactly the behaviour that is now wrong — a canonical timeoutMs has no case at all.
  3. The ADR-0087 conversion makes it worse, not better. turso-config-timeout-to-timeout-ms (protocol 18, registered on the same stack) rewrites a stored config.timeout to timeoutMs on load. So after the conversion replays, the bag holds timeoutMs and this reader finds nothing — the conversion and the reader now disagree by construction.

Blast radius today

Bounded, and worth stating precisely rather than overstating: TursoDriverConfig.timeout is itself never forwarded to @libsql/client (a separate finding, filed alongside this one), so no operation changes its timeout as a result. What is broken is the seam: the reader table's whole design property — "read every key, enforced by a mapped type over Required of the config" — is true of the KEY LIST and silent about the SPELLING each reader consults, and this is the first spelling to move.

Suggested repair

Read config.timeoutMs, and give the test a case authored the canonical way. Whether the retired spelling should still be read as a fallback for stored rows that never met the conversion is the actual decision here — the sibling authToken reader keeps a legacy arm on purpose and documents why (#8152), so this is not obvious either way and belongs to whoever owns the seam.

Related: #14478 · #15680 · #15682

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions