Skip to content

fix: propose an organization slug from the first name, not the possessive sentence - #341

Merged
fclairamb merged 5 commits into
mainfrom
batch/2026-09-07
Sep 7, 2026
Merged

fclairamb merged 5 commits into
mainfrom
batch/2026-09-07

Conversation

@fclairamb

Copy link
Copy Markdown
Owner

One spec, implemented in isolation and cleared by an independent audit before being archived to specs/done/2026/09/.

The problem

v0.25.0 shipped a pre-filled create form on /no-org: a brand-new account is offered "Florent's organization". The card submits with no slug and the server derives one from the display name — but the display name is a localized sentence, so the slug became the sentence, truncated at 20 characters:

Locale Proposal Slug the user got
en Florent's organization florents-organizatio
fr L'organisation de Florent lorganisation-de-flo
de Organisation von Florent organisation-von-flo
es Organización de Florent organizacin-de-flore

Three things wrong with that on the one screen whose entire job is "here is an organization for you, click Create":

  • Every personal org in a locale shares a prefix — the boilerplate leads, and the part that identifies the person sits exactly where the cap cuts.
  • The name is what gets truncated. A Florent and a Florence on a French install both become lorganisation-de-flo, the second with a collision suffix on top.
  • Non-Latin names vanish entirely. 李雷's organization normalized to s-organization.

The UI also showed this slug in the "Will be reachable as…" line and seeded the Advanced field with it, so anyone wanting a better address started by deleting florents-organizatio by hand.

The fix

The display name is unchanged — the localized possessive was a deliberate choice and stays. What changes is where the slug comes from: the first name, proposed by a new pure helper, shown in the preview, and sent to the server as a hint.

POST /api/v1/orgs gains an optional slugBase. The distinction from slug is the point:

  • slug stays strict — taken literally, 422 if invalid, 409 if taken, never fixed up. Unchanged.
  • slugBase is a hint — normalized, suffixed 2/3/… on collision, and silently ignored when unusable. It never answers 422 or 409.

That is what keeps the guarantee v0.25.0 set out to give: a newcomer who accepts the proposal never meets an error they cannot act on. Sending slug: "florent" strictly would hand the second Florent a 409; retrying florent2 from the browser would re-implement the server's collision handling with a race. One optional field is smaller than either.

李雷 now falls back to the seeded random name (bright-falcon) rather than losing the name entirely.

Deliberately unchanged

The strict slug contract, Slugify's 20-character cap (the input was wrong, not the cap), and the org's localized display name.

QA

Backend build, lint and full test suite green; dash0 build, lint and 1377 unit tests green. dash0 ESLint holds at its 42-error pre-existing baseline with none new.

The E2E was run, not just authored — the /no-org block in create-org.spec.ts now asserts the exact previewed slug, that Advanced seeds it, that Create with nothing typed lands on that exact org address, and that the display name is still the possessive sentence. Backend tests cover the hint's precedence, normalization and collision suffixing, with positive controls proving the strict path still answers 409 and 422.

🤖 Generated with Claude Code

fclairamb and others added 5 commits September 7, 2026 08:36
…tence

/no-org's create-org preview and submission derived the slug from the
localized display sentence ("L'organisation de Florent"), so every locale's
proposal shared the same boilerplate prefix and the 20-char cap truncated the
one part that identified the person. Add suggestedSlugBase() to derive the
slug from the first name instead, and a new slugBase request hint (server:
CreateOrgRequest.SlugBase, consulted by GenerateUnique only when slug is
omitted, never answering 422/409) so the server keeps owning collision
handling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ion handling

Proves the new CreateOrgRequest.SlugBase field for spec 2026-09-07-01: it wins
over Name when present, is normalized/suffixed like any other candidate,
falls through silently when unusable, is entirely ignored once an explicit
Slug is supplied, and does not soften the strict slug contract (still 422
invalid / 409 taken) on the same request path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Extends the existing "/no-org proposes an organization" block for spec
2026-09-07-01: the slug preview and the Advanced-seeded field must read
exactly the lowercased first name (not merely contain it), Create must land
on that exact slug, and the org's display name must still be the possessive
sentence. Switches the fixture name to a unique-per-run "Zoe<stamp36>" so the
exact-match assertions stay correct on a persistent dev database.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
build-backend, lint-back, full backend test suite (go test ./... -short),
build-dash0, dash0 eslint (no new errors), dash0 vitest unit tests, and the
extended create-org.spec.ts E2E block (run against a side-car server, all 3
tests green) all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@fclairamb
fclairamb enabled auto-merge (squash) September 7, 2026 06:50
@fclairamb
fclairamb merged commit 83e6e27 into main Sep 7, 2026
13 checks passed
@fclairamb
fclairamb deleted the batch/2026-09-07 branch September 7, 2026 07:24
@fclairamb fclairamb mentioned this pull request Sep 7, 2026
fclairamb added a commit that referenced this pull request Sep 7, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.25.1](v0.25.0...v0.25.1)
(2026-09-07)


### Bug Fixes

* **deps:** update github.com/dop251/goja digest to 70ad66e
([#338](#338))
([7bae0fe](7bae0fe))
* propose an organization slug from the first name, not the possessive
sentence ([#341](#341))
([83e6e27](83e6e27))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant