Skip to content

GET /api/codebases dedupes by its own URL normalization instead of remoteIdentity #4407

Closed

Description

@Wirasm

Problem

GET /api/codebases removes duplicate projects before returning the list. It builds the dedupe key with its own normalizer, normalizeUrl = (url) => url.replace(/\.git$/, '') (packages/server/src/routes/api.ts:3411, used at :3419). Registration decides whether two URLs are the same remote with remoteIdentity (packages/core/src/services/project-registration-identity.ts:129-153). That function strips trailing slashes before .git, parses SCP-style SSH remotes and URLs into host/path, lowercases the host, and lowercases the path on github.com.

The two disagree today. Registration treats https://github.com/acme/api/, https://github.com/acme/api.git, git@github.com:acme/api.git and https://github.com/Acme/API as one remote. The listing treats them as up to four different projects. In the other direction, the listing can merge rows that registration would keep separate on a non-GitHub host, because it compares raw strings without parsing the host.

Why it is worth solving

Two sites that must agree on what counts as one remote are kept in agreement by discipline, and they already disagree. Registration refuses a second project on an already registered remote, so duplicate rows today come from legacy databases and from the update and repair paths. Those are the rows this dedupe exists to collapse, and its weaker key fails to collapse the common spelling variants.

Why now

Recent registration work (PR 4237) moved remote ownership onto remoteIdentity and its owner lookup in packages/core/src/services/registration-remote.ts. The listing's copy is now the only remaining hand-written remote-equality rule on this path.

Desired outcome

One definition of remote equality. Either the listing derives its key from the same identity registration uses, or the dedupe is removed if the implementer shows it no longer protects a reachable state. The implementer chooses which, and says why in the pull request.

Invariants

  • Rows without repository_url are never collapsed, as today.
  • When rows are collapsed, the most recently updated one is kept, as today.
  • No database schema change.
  • The route's response shape is unchanged.

Acceptance

  • Two codebases whose repository_url values differ only by a trailing slash, a .git suffix, or SSH vs HTTPS spelling of one GitHub remote appear once in GET /api/codebases, or the dedupe is gone with a stated reason.
  • A test exercises the listing with at least the trailing-slash and SSH/HTTPS spellings, and fails on the current normalizeUrl.
  • No second remote-normalization function remains in packages/server/src/routes/api.ts.

Found by Archon run 16f45747-248c-4419-b561-937e6a69772c and verified at c47d37a by the archon-discoveries workflow.

Current scope (maintainer ruling on the build queue's question on a stopped run, 2026-10-20)

GET /api/codebases must remain available when a stored local remote identity cannot be resolved. Retain each unresolved row separately, report the failure observably, and do not infer equality for it or introduce another remote-normalization rule. All existing issue invariants remain.

The maintainer's words: Keep the list available. One broken local remote must not hide every healthy project, and the operator needs the broken one in the list to find and fix it. Rows whose identity can't be resolved are returned as they are, not deduplicated, and each one logs a warning that names the codebase and the original error. No new response fields unless the plan already needs one.

Activity

  1. added
    archon-planTriage: ready; a plan comes before delivery
    archon-size-mTriage: several files or two surfaces
    archon-type-bugTriage: something that worked is broken
    area: serverHTTP server (packages/server) - API routes, SSE, adapters
    on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    archon-planTriage: ready; a plan comes before deliveryarchon-size-mTriage: several files or two surfacesarchon-type-bugTriage: something that worked is brokenarea: serverHTTP server (packages/server) - API routes, SSE, adapters

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      Sponsor
      SponsoredKunjungi sekarang
      Promo