* fix(labels): enforce per-tenant uniqueness on NormalizedName
Finish the unused Label.NormalizedName contract the same way Secrets
does: unique (TenantId, NormalizedName) in EF, fail-closed Memory saves,
and keep NormalizedName in sync with Name.
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
* fix(labels): clone Memory label reads so a rejected rename cannot persist
Find/List handed out live store refs. Labels.Update mutates Name (and
NormalizedName) on that instance before Save; a uniqueness rejection
then left the stored row already renamed. Clone-on-read matches Memory
identity stores from #8108.
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
* fix(labels): stamp null TenantId, fail-loud on leftover duplicates, cap names at 255
Follow the Architect steer for Greptile P1s: do not auto-delete duplicate
labels; UPDATE Labels SET TenantId = '' WHERE TenantId IS NULL on every
provider before CreateIndex; keep SQL Server/Oracle filtered unique
indexes; HasMaxLength(255) on Name and NormalizedName with no silent
truncate.
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
* fix(labels): fail-loud preflight for leftover keys and over-length names
No silent dedupe: every provider lists leftover (TenantId, NormalizedName)
keys and aborts before CreateIndex. SQL Server/Oracle keep their filtered
unique indexes. PostgreSQL/SQLite keep provider column types. Providers
that narrow Name/NormalizedName to 255 preflight over-length Ids first.
Memory uniqueness semantics are unchanged.
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
* test(labels): match Oracle filtered-index escape in migration assertion
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>