Skip to content

Implementation/73146 update admin flow for sematic work package identifiers against project historical identifiers model#22442

Merged
akabiru merged 0 commit intoopen-point/73149-how-do-we-handle-project-identifiers-case-insensitive-storagefrom
implementation/73146-update-administration-setting-for-sematic-work-package-identifiers-ui-against-project-historical-identifiers-model
Mar 23, 2026
Merged

Implementation/73146 update admin flow for sematic work package identifiers against project historical identifiers model#22442
akabiru merged 0 commit intoopen-point/73149-how-do-we-handle-project-identifiers-case-insensitive-storagefrom
implementation/73146-update-administration-setting-for-sematic-work-package-identifiers-ui-against-project-historical-identifiers-model

Conversation

@akabiru
Copy link
Member

@akabiru akabiru commented Mar 20, 2026

Ticket

https://community.openproject.org/work_packages/73146

What are you trying to accomplish?

Extract ProblematicIdentifiers and wire up historical identifier exclusion.

Prepare the identifier autofix pipeline for the batch migration job by extracting shared logic from PreviewQuery into a reusable ProblematicIdentifiers class, and wiring up reserved identifier detection against real FriendlyId slug history.

What approach did you choose and why?

PreviewQuery mixed orchestration with scope-building and classification logic. Since the batch migration job will need the same scope and classification, extracting ProblematicIdentifiers avoids future duplication.

Reserved identifiers query friendly_id_slugs for historical project slugs that don't match any current active identifier -- these are "retired" identifiers locked to their original project by the identifier_not_historically_reserved validation.

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc) N/A -- backend-only
  • Tested major browsers (Chrome, Firefox, Edge, ...) N/A -- no UI changes

@akabiru akabiru self-assigned this Mar 20, 2026
@akabiru akabiru changed the title Implementation/73146 update administration setting for sematic work package identifiers UI against project historical identifiers model Implementation/73146 update admin flow for sematic work package identifiers against project historical identifiers model Mar 20, 2026
@akabiru akabiru marked this pull request as ready for review March 23, 2026 05:23
@akabiru akabiru requested review from a team and Copilot March 23, 2026 05:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Work Package identifier autofix preview pipeline by extracting identifier scope/classification logic into a reusable ProblematicIdentifiers service, and updates reserved identifier detection to use FriendlyId slug history (historical project identifiers).

Changes:

  • Extracted identifier scope, classification (error_reason), and exclusion building into WorkPackages::IdentifierAutofix::ProblematicIdentifiers.
  • Updated PreviewQuery to delegate scope/count/classification/exclusions to ProblematicIdentifiers.
  • Updated i18n + specs to reflect the renamed error reason (:not_fully_uppercased) and added dedicated unit tests for the new service.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
app/services/work_packages/identifier_autofix/problematic_identifiers.rb New shared service for problematic-project scoping, error classification, and exclusion set (incl. FriendlyId history).
app/services/work_packages/identifier_autofix/preview_query.rb Simplifies preview orchestration by delegating analysis and exclusions to ProblematicIdentifiers.
spec/services/work_packages/identifier_autofix/problematic_identifiers_spec.rb New unit coverage for ProblematicIdentifiers behavior (scope, count, reasons, exclusion set).
spec/services/work_packages/identifier_autofix/preview_query_spec.rb Aligns preview specs with extracted analysis service and renamed error reason.
config/locales/en.yml Renames translation key for the uppercase-related error reason.

Comment on lines +108 to +113
def reserved_identifiers
@reserved_identifiers ||= FriendlyId::Slug
.where(sluggable_type: Project.name)
.where.not(slug: Project.select(:identifier))
.pluck(:slug)
.to_set
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reserved_identifiers is collected case-sensitively, but Projects::Identifier#identifier_not_historically_reserved checks slug history case-insensitively (LOWER comparison). This can lead to the suggestion generator proposing an identifier that later fails validation due to a differently-cased historical slug. Consider normalizing both sides (e.g., pluck lower/upper-cased slugs and compare against normalized project identifiers, and normalize the identifier passed into reserved_identifiers/include? checks accordingly).

Copilot uses AI. Check for mistakes.
RSpec.describe WorkPackages::IdentifierAutofix::ProblematicIdentifiers do
subject(:analysis) { described_class.new }

let(:max_length) { WorkPackages::IdentifierAutofix::ProjectIdentifierSuggestionGenerator::IDENTIFIER_LENGTH[:max] }
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let(:max_length) is defined but never used in this spec. This can trip RSpec/UnusedLet and adds noise—either remove it or use it in the expectations (e.g., build an identifier based on max_length).

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +123
it "returns :reserved when identifier is a historical slug of another project" do
project = create_valid_project(name: "Gamma", identifier: "GAMMA")
FriendlyId::Slug.create!(slug: "OLDIE", sluggable: Project.find(project.id), sluggable_type: "Project")

expect(analysis.error_reason("OLDIE")).to eq(:reserved)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example description says the slug is from “another project”, but the test creates the slug on the same project it just created. Please adjust the wording or create a second project so the spec matches the scenario being described.

Copilot uses AI. Check for mistakes.
@akabiru akabiru merged commit 6c84213 into open-point/73149-how-do-we-handle-project-identifiers-case-insensitive-storage Mar 23, 2026
15 of 16 checks passed
@akabiru akabiru force-pushed the open-point/73149-how-do-we-handle-project-identifiers-case-insensitive-storage branch from 0738f98 to 5c7bed1 Compare March 23, 2026 14:25
@akabiru akabiru deleted the implementation/73146-update-administration-setting-for-sematic-work-package-identifiers-ui-against-project-historical-identifiers-model branch March 23, 2026 14:25
@github-actions github-actions bot locked and limited conversation to collaborators Mar 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants