Repository navigation
Description
domain:server#7 · os-tesla · session_01L9qibzKCovWpJoMZD6U3NT
Filing gate: ① product defect, located by reading the code with its mechanism written down (reach: a named real producer, driver-sql's widening arm, on every MySQL 8 database upgraded from a release that had the narrower key). Found by the red-line read of #33199 (round-1 design finding M4), declared there as a limit.
Business rationale
Who: an operator running on MySQL 8.0.13+ who upgraded a database created before ADR-0150 widened three platform keys to carry the package. What breaks: the old, narrower unique key is never retired, so the database keeps refusing exactly what the widening exists to admit:
sys_user_permission_set(plugin-security + runtime: the grant, clone and activation doors take a permission set's package and report a two-holder name with its candidates (ADR-0150 D3/D8; before #31698 PR-2) #32164): one user cannot hold two packages' permission sets of one name in one organization.sys_connector_connection(feat(service-automation, metadata-protocol, driver-mongodb, cli): a connector connection is unique per organization and instance (package, name) #33199, objectql: narrow the phase-1 one-holder refusal from environment to namespace for webhook, connector and email_template (ADR-0150 child B, webhook family) #31699): one organization cannot connect two packages' connector instances of one name.sys_metadata_activation(core: activation ledger unique (metadata_type, package_id, name), backfilled (ADR-0150 child S1) #31682): read from the same code; the activation ledger's MySQL guard takes the same functional form, so the ledger's old(metadata_type, name)key is kept too. Not measured.
Each is unreachable while the phase-1 one-holder backstop keeps a name to one package, and becomes a refusal the user cannot get past (no prescription names it) once ADR-0150's narrowing lands for that type. SQLite, PostgreSQL, MariaDB 10.3+ and MongoDB retire the old key; a database created fresh on MySQL never has it. If not fixed: MySQL deployments silently keep phase-1 behaviour for these tables after the platform moves on.
Mechanism
- The guard on MySQL is a UNIQUE key over a functional key part, the driver's hash-shadow digest, NULL for a packaged row (
packages/metadata-protocol/src/migrations/*-packageless-index.ts, MySQL branch). - Introspection records that key part as an expression (
packages/drivers/driver-sql/src/sql-driver-introspection.ts, theEXPRESSIONbranch of the MySQL statistics read). hasPartialUniqueGuard(packages/drivers/driver-sql/src/schema-drift.ts) accepts onlypartial === truewith no expressions, so the guard never counts, andwidenedUniqueReplacementskeeps the old key (kept), with no plan op ever offered.- Pinned as the declared limit in
packages/drivers/driver-sql/src/sql-driver-widened-connection-key.test.ts(MySQL cell: no index op, a second package's row refused).
Acceptance
driver-sqlrecognises the platform's MySQL functional-digest guard (the digest expression over exactly the narrower columns, NULL when the gained column is non-null) as a partial unique on those columns, so the arm plans the same safereplace_unique_indexas on PostgreSQL.- The MySQL cells of the three widened-key suites flip from the declared limit to the replace; MariaDB unchanged.
- The declared-limit sentences go (changesets of plugin-security + runtime: the grant, clone and activation doors take a permission set's package and report a two-holder name with its candidates (ADR-0150 D3/D8; before #31698 PR-2) #32164 and feat(service-automation, metadata-protocol, driver-mongodb, cli): a connector connection is unique per organization and instance (package, name) #33199 are released text; the new changeset says FROM kept TO retired, plus
content/docs/deployment/cli.mdx"Runtime-owned indexes apply builds").
Who acts
The server lane's driver-sql owner, as one PR after #33199 lands (it adds the connection table's MySQL cell this card flips). Not folded into #31699: it is a driver change across three tables.
Duplicate search
gh api search/issues over this repo, issues: hasPartialUniqueGuard 2 hits (#31699, #32164, neither tracks it); MySQL functional key part guard 26 (#31732 is the MongoDB analogue, closed; none for MySQL); widening arm MySQL 228, first page none; packageless MySQL expression 4, none.
Activity
objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first touch →
domain:server· p3 ·pm:queue· 2026-11-14T02:45Z⛔ Not a claim.
epic:#31527#3may fold it with metadata-protocol: after a restart, two stored rows of one name that each name a different holder leave only the last one loaded, for every package-slotted type (tool, webhook, …) #33127 / metadata-protocol: the registry's bare slot keeps only the row hydrated last when a pair row and a package-less row of the same member are both stored #32900 if it touches the same key code.