DI exec: applied CC-DI Subagent A+B SQL — 3245 clanovi, Manuel Boras merged

This commit is contained in:
2026-05-05 09:04:14 +02:00
parent e7102c720d
commit 4e4d69c04a
6 changed files with 451 additions and 2 deletions
@@ -0,0 +1,61 @@
# Subagent D — Schema Quality Constraints (pgz_sport.clanovi)
Date: 2026-05-05
Live row count: 3240 (backup retained at `pgz_sport.clanovi_backup_20260505_0836` = 3243)
## Summary table
| # | Candidate | Type | Pre-flight violators | Status | Object name |
|---|-----------|------|----------------------|--------|-------------|
| C1 | No internal CamelCase boundary | CHECK | 0 | APPLIED | `clanovi_no_camelcase_chk` |
| C2 | ime/prezime trimmed | CHECK | 0 | APPLIED | `clanovi_trimmed_chk` |
| C3 | length(ime) >= 2 AND length(prezime) >= 2 | CHECK | 22 | SKIPPED (see D_violations.md) | — |
| C4 | spol IN ('M','Ž',NULL) | CHECK | 0 | ALREADY PRESENT | `clanovi_spol_check` (pre-existing) |
| C5 | hns_igrac_id partial UNIQUE | UNIQUE INDEX | 0 dup-groups | APPLIED | `clanovi_hns_uniq` |
| C6 | (klub_id, lower(ime), lower(prezime), datum_rodenja) UNIQUE | UNIQUE INDEX | 68 dup-groups | SKIPPED (see D_violations.md) | — |
| C7 | BEFORE INSERT/UPDATE normalize trigger | TRIGGER | n/a | APPLIED | `clanovi_normalize_trigger` + `pgz_sport.clanovi_normalize_fn()` |
## Trigger semantics
`clanovi_normalize_fn`:
1. Always `trim()` `NEW.ime` and `NEW.prezime`.
2. On `INSERT`, or on `UPDATE` only when `ime` or `prezime` actually change:
- reject CamelCase boundary (lenient: only ascii+Croatian-diacritic lower→upper pairs);
- reject `length(ime) < 2` or `length(prezime) < 2`.
3. The "only-when-name-changes" rule preserves the 22 legitimate historical short-name rows (e.g. `id=1852..2141`, mostly placeholder `'-'` ime + surname-only entries) so they can still receive `UPDATE`s on other fields.
## Smoke insert tests (all wrapped in BEGIN/ROLLBACK so live data unchanged)
| # | Scenario | Expected | Result |
|---|----------|----------|--------|
| 1 | INSERT `('IvoIvic','Test')` | reject (CamelCase) | REJECTED — `CamelCase rejected in ime: IvoIvic` |
| 2 | INSERT `('PetarPan','Test')` | reject | REJECTED |
| 3 | INSERT `(' Ivo ',' Ivić ')` | trim then succeed | INSERTED — stored as `('Ivo','Ivić')` |
| 4 | INSERT `('A','Test')` | reject (length) | REJECTED — `ime too short (<2 chars): A` |
| 5 | INSERT `('Ivan',' X ')` | trim → `'X'` len 1 → reject | REJECTED — `prezime too short (<2 chars): X` |
| 6 | INSERT `('Marko ',' Marković')` | trim then succeed | INSERTED — stored as `('Marko','Marković')` |
| 7 | INSERT duplicate `hns_igrac_id='209352'` | reject | REJECTED — `duplicate key value violates unique constraint "clanovi_hns_uniq"` |
| 8 | 2× NULL + 2× `''` `hns_igrac_id` rows | all 4 succeed (partial uniqueness ignores NULL/empty) | 4 INSERTS OK |
| 9 | UPDATE `id=1852` (`ime='-'`) `napomena=...` (no name change) | succeed | UPDATED — short-name row still mutable |
| 10 | UPDATE `id=1852` `ime='?'` (single char) | reject | REJECTED — `ime too short (<2 chars): ?` |
All 10 behaviours match expectations. No live row was modified — every test ROLLBACKed.
## Final lockdown state on `pgz_sport.clanovi`
CHECK constraints in force:
- `clanovi_no_camelcase_chk` (NEW)
- `clanovi_trimmed_chk` (NEW)
- `clanovi_spol_check` (pre-existing)
UNIQUE indexes in force:
- `clanovi_pkey` (id)
- `uq_clanovi_klub_profile` (klub_id, profile_url) — pre-existing
- `clanovi_hns_uniq` (hns_igrac_id) WHERE not null/empty — NEW
User triggers in force (BEFORE INSERT OR UPDATE):
- `clanovi_normalize_trigger` (NEW)
- `clanovi_validate_source` (pre-existing)
- `pgz_sport_clanovi_fts_trg` (pre-existing)
Row count unchanged at 3240.