Use core's slug rule for project status slugs - #36
Merged
Conversation
project_status.ex stripped every non-ASCII character, so a Cyrillic or Greek status name produced an EMPTY slug — and statuses are looked up BY slug (Statuses.current_status/1 treats "" as nil), so the status silently vanished. Now delegates to PhoenixKit.Utils.Slug (backed by locale_slug). Requires the phoenix_kit release carrying the locale-aware Slug (BeamLabEU/phoenix_kit#692).⚠️ This repo does not currently compile against local core for a reason unrelated to this change: project_form_live.ex and template_form_live.ex call `ai_multilang_tabs/1`, which needs a newer phoenix_kit_ai than is resolved. The same failure occurs with this change stashed.
Verified the new behaviour by hand but never pinned it, which is exactly the gap a delta audit exists to catch: without these, reverting the slug change leaves the suite green. Asserts Cyrillic and Greek now produce a real slug rather than an empty one, that German keeps its letters, and that plain ASCII is unchanged.
Caught by the upstream review of phoenix_kit_dashboards#5, which found the same defect there and had to repair it after merge. PhoenixKit.Utils.Slug.slugify/2 defaults :transliterate to FALSE on every core released so far. So `Slug.slugify(text)` strips every non-ASCII character — exactly what the local pipeline this change replaced did. The delegation was correct and the behaviour was unchanged. My verification missed it because I tested against local core, where I had made transliteration the default. Against the core these modules actually resolve, it was inert. That is the difference between "the code is right" and "the shipped artifact is right", and only the second one matters. Forward-compatible: once core ships the locale-aware Slug, :transliterate is accepted and ignored, so this stays correct. The pinning tests are rewritten to assert only what holds at EVERY core version. Asserting output was the second half of the same mistake: each module resolves a different core (posts' lockfile pins 1.7.189, which predates the :transliterate option entirely), so a literal expected slug merges red.
ddon
added a commit
that referenced
this pull request
Aug 10, 2026
Core pin moves to ~> 2.0. This package does not call migration internals, so the change is the pin itself. Merge PR #36 (core slug rule for status slugs) and add @impl true to source_fields/2, now that ai 0.18.0 declares it on the FormBinding behaviour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This module had its own hand-rolled slugifier:
That deletes every non-ASCII character, so a Cyrillic or Greek name produced an empty
slug, and German lost its umlauts and ß:
Видеопродакшн""videoprodakshnΚαλημέρα""kalimeraGröße Fußballgre-fuballgrosse-fussballAn empty slug is worse than a wrong one: callers read it as "no slug yet" and regenerate
on every save.
It now delegates to
PhoenixKit.Utils.Slug, backed by thelocale_slugpackage — one implementation for thewhole ecosystem instead of a copy per repo.
Stored slugs are not rewritten; generation only runs when the slug is blank, so
existing URLs are untouched.
Release order
phoenix_kitrelease carrying the locale-awareSlug, currently inBeamLabEU/phoenix_kit#692. Does not build against the published core until that ships.
Merge order: core release → this.
Scope
project_status.ex. Worth noting statuses are looked up by slug, andStatuses.current_status/1treats""asnil— so a Cyrillic status name did notmerely get an ugly URL, it silently vanished.
Verification
New
slug_generation_test.exspins the behaviour.1387 tests, 0 failures against local core.
(An earlier revision of this description claimed the repo does not compile against local
core because of
ai_multilang_tabs/1. That was my testing setup, not the repo: it needsPHOENIX_KIT_AI_PATHalongsidePHOENIX_KIT_PATH, since the function lives inphoenix_kit_ai0.17. With both exported it compiles and the suite is green.)