18.8: table_sync_function causes PG::UniqueViolation on git-upload-pack, breaking all CI pipelines after first run per day
### Summary
After upgrading to GitLab 18.8.x, all CI pipeline jobs fail at the git clone step.
Root cause: a PostgreSQL trigger `table_sync_function_c237afdf68()` introduced by a
18.8 batched background migration causes `PG::UniqueViolation` on every
`POST /git-upload-pack` request except the first one per day per project.
### Steps to reproduce
1. Upgrade GitLab self-managed (Omnibus) to 18.8.x
2. Run a CI pipeline that clones a repository — first pipeline of the day succeeds
3. Run any subsequent pipeline for the same project the same day — it fails at git clone
### Example Project
N/A (self-managed only, reproducible on any project after the first clone per day)
### What is the current *bug* behavior?
All CI pipelines after the first one per day fail at git clone:
```
error: expected flush after ref listing
fatal: the remote end hung up unexpectedly
```
GitLab returns HTTP 500 on `POST /git-upload-pack`.
### What is the expected *correct* behavior?
All CI pipelines clone the repository successfully regardless of how many times
they run per day.
### Relevant logs and/or screenshots
From `production_json.log` (captured via correlation ID from workhorse log):
```json
{
"exception.class": "ActiveRecord::RecordNotUnique",
"exception.message": "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint \"index_project_daily_statistics_on_project_id_and_date\"\nDETAIL: Key (project_id, date)=(15, 2026-03-06) already exists.\nCONTEXT: SQL statement \"INSERT INTO project_daily_statistics_archived (\\\"id\\\", \\\"project_id\\\", \\\"fetch_count\\\", \\\"date\\\") VALUES (NEW.\\\"id\\\", NEW.\\\"project_id\\\", NEW.\\\"fetch_count\\\", NEW.\\\"date\\\")\"\n PL/pgSQL function table_sync_function_c237afdf68() line 12 at SQL statement",
"controller": "Repositories::GitHttpController",
"action": "git_upload_pack"
}
```
Call chain:
```
Repositories::GitHttpController#git_upload_pack
→ FetchStatisticsIncrementService#execute
→ ProjectDailyStatistic.upsert (ON CONFLICT DO NOTHING — safe)
→ trigger table_sync_function_c237afdf68() fires on INSERT
→ INSERT INTO project_daily_statistics_archived ← missing ON CONFLICT DO NOTHING
→ PG::UniqueViolation on second fetch same day
→ HTTP 500 → git receives invalid response → "expected flush after ref listing"
```
### Output of checks
#### Results of GitLab environment info
<details>
<summary>Expand for output related to GitLab environment info</summary>
<pre>
GitLab version: 18.8.5-ee
Installation type: omnibus (Docker)
PostgreSQL: bundled
</pre>
</details>
### Possible fixes
The trigger function `table_sync_function_c237afdf68()` is missing `ON CONFLICT DO NOTHING`
in its INSERT branch. Current body (line 12):
```sql
INSERT INTO project_daily_statistics_archived ("id", "project_id", "fetch_count", "date")
VALUES (NEW."id", NEW."project_id", NEW."fetch_count", NEW."date");
```
Fix — add `ON CONFLICT DO NOTHING`:
```sql
INSERT INTO project_daily_statistics_archived ("id", "project_id", "fetch_count", "date")
VALUES (NEW."id", NEW."project_id", NEW."fetch_count", NEW."date")
ON CONFLICT DO NOTHING;
```
**Workaround** (apply directly in PostgreSQL until fix is released):
```sql
CREATE OR REPLACE FUNCTION public.table_sync_function_c237afdf68()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
IF (TG_OP = 'DELETE') THEN
DELETE FROM project_daily_statistics_archived where "id" = OLD."id";
ELSIF (TG_OP = 'UPDATE') THEN
UPDATE project_daily_statistics_archived
SET "project_id" = NEW."project_id",
"fetch_count" = NEW."fetch_count",
"date" = NEW."date"
WHERE project_daily_statistics_archived."id" = NEW."id";
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO project_daily_statistics_archived ("id", "project_id", "fetch_count", "date")
VALUES (NEW."id", NEW."project_id", NEW."fetch_count", NEW."date")
ON CONFLICT DO NOTHING;
END IF;
RETURN NULL;
END
$function$;
```
issue