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.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions