Skip to content

De-fallback driver-sql's autonumber format — drop the two hardcoded || '{0000}' sites for the declared default (#6555 half 3/3) #7263

Description

@os-zhuang

Blocked-by: #6555's spec-half PR (branch claude/issue-6555-autonumber-default-format) — the declared default must exist before this reads it.

Execution half of the maintainer's route-3 ruling on #6555. Filed unassigned and unrouted; triage routes it (the ruling says drivers).

The ruling (verbatim, comment 5225535766)

Maintainer ruling (2026-08-08): Route 3, with the default fixed at {0000}. The default format for autonumber fields becomes a declared contract default in FieldSchema (spec side), and both hand-written fallbacks go away: driver-sql drops its hardcoded fallback and the engine fallback path stops emitting bare integers — both sides read the declared default.

Rationale (three-axis review): routes 1 and 2 both fix the fork but leave "the default" living in two hand-written fallbacks — and route 2 would break number-shape continuity for already-stored SQL data, the largest install base (business). Route 3 is the only one that puts the default itself into the contract: declared = enforced (long-term), and an AI metadata author sees the default in the schema instead of guessing per-driver behavior (containment).

Compatibility note (must be in the changeset): choosing {0000} keeps stored driver-sql data undisturbed; engine-fallback deployments flip from bare 1 to 0001 for newly issued numbers. Counter continuity itself is unaffected (#6468 pinned it).

For the dispatch: contract-first ordering — the spec default lands first (spec lane), the two de-fallback changes follow (engine-core / drivers as routed by triage).

The change

packages/drivers/driver-sql/src/sql-driver.ts — two sites, re-measured on origin/main @ 3566e55 (they drifted again from the :4330/:4412 triage cited, and from the :4322/:4404 in #6555's body):

  • :5350-5353initObjects
  • :5432-5435 — the external-object registration path

Both spell the same six lines:

const rawFmt = (typeof field.autonumberFormat === 'string' && field.autonumberFormat)
  ? field.autonumberFormat
  : (typeof field.format === 'string' && field.format ? field.format : '');
const fmt = rawFmt || '{0000}';

Replace each with the contract:

const fmt = resolveAutonumberFormat(field);

resolveAutonumberFormat is exported from @objectstack/spec/data by the blocking PR, and was written to reproduce exactly this precedence — canonical autonumberFormat, then the format shorthand (#1603), then DEFAULT_AUTONUMBER_FORMAT for anything that is not a non-empty string.

Behaviour-neutral by construction — that is the point of this card

Unlike its engine sibling, this half moves nothing: resolveAutonumberFormat's truthiness rule was deliberately taken from these very lines so already-stored SQL record numbers keep their shape, per the ruling's compatibility note. It should land as a pure de-duplication: the default stops being written down in the driver and is read from the contract instead.

That makes the review question a narrow one — prove the substitution is exact, including the format: '' and non-string cases, not just the happy path.

Suggested gates

  • All eight packages/drivers/driver-sql/src/sql-driver-autonumber-*.test.ts suites — every one must stay green unchanged. A test that needs editing here is a signal the substitution is not exact.
  • In particular the legacy case in sql-driver-autonumber-suffix.test.ts, which pins '0011' and names this divergence in its comment (PR fix(objectql,driver-sql): 播种解析按声明的 suffix 定位计数器,两侧收敛 (#6468) #6553) — with this card landed, that comment can point at the declared default instead of at a local fallback.
  • packages/runtime/src/autonumber-seed-cross-side-parity.integration.test.ts.
  • Changeset carrying the compatibility note verbatim.

Not in this card

The engine's applyAutonumbers path — its own card. #6555 stays open until both land.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions