# Implementation Plan v2: Autonumber Engine v2 Cutover (PRD v3.1)

> **v2 supersedes v1.** Changes incorporated from Round-2 dual-model review (Pass A architect: 5 P1 findings; Pass B adversarial: 5 CRITICAL + 7 HIGH findings) + user decisions 2026-04-17. PRD remains authoritative; this plan executes it.

## 0. Round-2 Fixpack Summary (v2 deltas)

| # | v1 issue | v2 fix | Source |
|---|----------|--------|--------|
| F1 | `GET_LOCK('autonumber_cutover')` nested under `nexuscrm_bootstrap_mutation` with per-batch release — window race | **Remove new lock entirely; reuse outer `nexuscrm_bootstrap_mutation`**. All seed UPSERT on same lockConn; no per-batch release | Pass B #1, user decision C |
| F2 | Lane C conflates format-seed (needs only B) with counter-seed (needs A) → Wave-2 parallelism blocked | Split into **C1 (format seed + RecordTypeCode)** in Wave 1 and **C2 (counter seed)** in Wave 2 | Pass A B1 |
| F3 | TDD Tier 2 item 5 merges case 17a (per_day legit) + 17b (global CORRUPTION) → implementer may mask distinction | Split into `H1-reserve-missing-perday-legit` and `H1-reserve-missing-global-corruption`; negative-assertion that `global` path never UPSERTs | Pass A C2 |
| F4 | 48h FE lock-degradation window between PR-1a and PR-1b | **PR-1a includes 3-LOC `MetadataRecordForm.tsx` Set fix**; full rewrite stays PR-1b | Pass A P1-3, user |
| F5 | Plan unilaterally ratified PRD §12.2 Q1/Q11/Q12 defaults | **User explicitly signs off**: Q1 fail-closed; Q11 Approach α; Q12 `caller_txn`. Plan §6 cites user confirmation | Pass A F1 |
| F6 | Bootstrap API replacing `UpsertAutoNumber` unnamed | **Named**: `autonumber.SeedFieldCounter(ctx, fieldID) error` (Lane A export); `field_create.go:192` calls this | Pass A F3 |
| F7 | `RecordTypeCode` NOT NULL DEFAULT '' bypass V6 (silent empty) | **Column = `VARCHAR(16) NULL`**; V6 checks `IS NOT NULL AND RecordTypeCode != ''`; seed uses UPDATE, not DEFAULT | Pass B #6, user Q11 |
| F8 | `GREATEST` cross-source lacks scope-awareness; legacy `_System_AutoNumber.CurrentNumber` semantic unclear per-field | **Per-field scope map in seed spec**: for scope=global, GREATEST over (live column max, legacy `_System_AutoNumber.CurrentNumber`, legacy `_System_CompoundAutoNumber.counter_state`, `auto_number_start`). Test 25/26 covers `legacy_global > live_today` | Pass B #5 |
| F9 | Quarantine state undefined persistence; engine init might crash on parse fail | **In-memory**; recomputed at every engine init; parse-fail marks QUARANTINED + logs + continues (NO crash) | Pass B #11 |
| F10 | Rollback: code revert vs rollback spec unordered | **Hard sequence in `docs/runbooks/autonumber.md`**: git revert → CI green → deploy → apply spec staging → verify → apply spec prod | Pass B #9 |
| F11 | TiDB optimistic mode defeats `FOR UPDATE` fallback serialization | **Engine forces `SET SESSION tidb_txn_mode = 'pessimistic'`** on reservation+fallback conns | Pass B #3 |
| F12 | J1 fuzz round-trip doesn't catch canon non-determinism | Add `canon(x) == canon(x)` assertion over 1000 inputs | Pass B #14 |
| F13 | `AssignBatch` mixed-bucket (10 countries × 100 recs) untested — degrades to 100× reserveOne | Add test **19b**: 1000 records × 10 scope-keys, assert throughput ≥ 200/s on `4Qbn3F3nyaU9DLk.root` | Pass B #15 |
| F14 | Seed partial-fail recovery path untested | Add test: synthetic unparseable row mid-scan → abort → remove row → re-apply → verify completes | Pass B #10 |
| F15 | Lane M (metrics + runbook + alert) all in PR-1a → inflates PR | **Split**: metric emissions (~30 LOC) stay PR-1a; runbook + alert yaml → PR-1c within 3 days post-merge | Pass B #16, user |
| F16 | No lint enforcement of canonicalizer single-ownership | CI grep: `grep -rE 'json\.Marshal\([^)]*[Tt]okenRefs' backend/` MUST return 0 hits | Pass B #7 |
| F17 | `verify-generated` CI not hooked for new generated file | New `platform_config_autonumber_formats.go` added to Makefile `verify-generated` target list | Pass B #21 |
| F18 | agent-browser FE evidence blind to hydration warnings | PR-1b evidence MUST include `browser_console_messages` dump with 0 hits on `hydration`/`did not match` | Pass B #22 |
| F19 | Connection pool may saturate on 3× parallel apply against shared branch | Every apply process forced `max_open_conns=10`; Phase-0 checklist item "no other consumers on branch for 45 min" | Pass B #4, #20 |
| F20 | Wave 3 lists D ‖ H-integration — but D+E is same-commit serial | Move D to **Wave 4 (serial)** alongside E; Wave 3 = H-integration ‖ M ‖ I only | Pass B #2 |
| F21 | Lane N (Phase-0 LOC spike) vs §1 LOC estimate conflict | **Keep Lane N**; §1 LOC table relabeled as "estimate; replaced by Lane N measurement before PR-1a opens" | Pass B #17 |
| F22 | LegacySource drop-order risk: if the legacy-drop data-spec applies before 100% of backend pods are on the cutover binary, any still-old pod's fallback read of `_System_AutoNumber` 404s → data loss. F8 scope-aware GREATEST only covers the seed path; this is a deploy-sequencing gap. | **Addressed by operator-enforced runbook — no machine gate** in `data-specs/2026-04-19-autonumber-v2-drop-legacy.md`. V2-R3 review (2026-04-19) confirmed that `data-spec-apply` does not wire `depends_on_commit_sha` / `precondition_check` / `cutover_order_warning` frontmatter keys, and that no `_System_Deployment` table exists — those keys were removed from the spec (V2-R3-C2) and replaced with an explicit operator warning block at the top of the markdown body. Required runbook sequence remains: (1) merge + deploy cutover binary to 100% pods; (2) wait ≥2h observed drain; (3) apply drop spec staging → verify → prod. Enforcement is on the operator, not the applier. A future follow-up may wire real deployment-state gates into `data-spec-apply`; tracked as an open item on the skill. | V1-H2 + V2-H4 Round-2 review; revised V2-R3-C2 |

**v2 kept from v1 (no change):**
- Lane map A-N overall structure
- 2-PR split (PR-1a backend cutover, PR-1b frontend)
- 三件套 verification matrix
- 4-quadrant review gate (schema + control-plane + concurrency + safety-regression)
- Test DB: local branch `4Qbn3F3nyaU9DLk.root` with `__pretest_bak_` snapshots
- Scope policy: all 132 fields ship as `scope=global` at cutover

---

## 1. Executive Summary

Replaces three legacy autonumber paths (`_System_AutoNumber` + `CompoundAutoNumberListener` + partial `identifier_engine`) with a single metadata-driven engine at `backend/internal/features/automation/autonumber/`, plus `_System_Field` columns + `_System_AutoNumberCounter` table + seed runner. Touches 5 subsystems.

**LOC estimate (v1 provisional; Lane N replaces before PR-1a opens):**

| Bucket | Raw LOC |
|---|---|
| New engine package | ~1400 |
| New schema + seed runner | ~450 |
| Generator + applyAutoNumberFormats | ~400 |
| Wiring | ~100 |
| Deletions | ~2850 |
| FE: MetadataRecordForm Set fix in PR-1a | 3 |
| Data-specs (seed + rollback) + SKILL | ~250 |
| Tests (17 unit + 13 integration + fuzz + partial-fail + 19b) | ~1600 |
| Metrics emissions (埋点 only — no runbook/alert) | ~30 |

Target PR-1a NET diff (ignoring test code): **~4400 / -2850 = NET +1550**. Total stat (add+del+tests): ~6600. Still exceeds 2500 single-PR target → **2-PR split confirmed**.

**Top-3 residual risks (after v2 fixpack):**

1. **`reserveOne` + TiDB pessimistic txn fallback** — §5.2 correctness ultimately depends on implementer not regressing sample-once / pre-seed / own-txn branches. Mitigated by split TDD (F3), sample-once test, pessimistic-mode setting (F11).
2. **Seed GREATEST cross-source semantic** — scope-aware mapping (F8) reduces risk but depends on data-spec correctness. Mitigated by test 25/26 + fail-closed unparseable + Phase-0 manual eye-check.
3. **Live cutover apply against running production DB** — not in PR-1a scope (PR-1a targets local test branch). Prod deploy is Phase-2 post-merge, outside this plan.

---

## 2. Task DAG (v2)

### 2.1 Lane map

| Lane | Work | Ships in | LOC (add) | LOC (del) | Parallelizable after | Risk |
|------|------|----------|-----------|-----------|----------------------|------|
| **A — Engine core** | `autonumber/` pkg: parser, renderer, reserveOne/Batch (pessimistic-forced), canonicalizer (with determinism fuzz), LRU semaphore, quarantine (in-memory), SeedFieldCounter export, metrics emissions | PR-1a | ~1430 | 0 | A0 (types) | **High** |
| **B — Schema** | `_System_Field` 6 cols + `_System_RecordType.RecordTypeCode VARCHAR(16) NULL` + `_System_AutoNumberCounter` + `z_generated_*.go` regen | PR-1a | ~300 | 0 | — | Med |
| **C1 — Format seed + RT codes** | `applyAutoNumberFormats` UPSERTs `_System_Field.auto_number_*` + UPDATE `_System_RecordType.RecordTypeCode` from generator | PR-1a | ~400 | ~110 | B | Low |
| **C2 — Counter seed runner** | `SeedAutoNumberCounters(ctx, rawDB)` — scope-aware GREATEST (F8), fail-closed on unparseable, under outer lock (F1, no new lock) | PR-1a | ~300 | 0 | A (parser), C1, B | **High** |
| **D — Persistence wiring** | Replace `generateAutoNumbers` at `persistence_insert.go:139` + `generateAutoNumbersBatch` at `persistence_bulk_insert.go:319`. Same commit as E | PR-1a | ~50 | ~120 | A, C2 | Med |
| **E — Legacy deletion** | rm listener + identifier_engine (5 files); delete `ensureStandardAutoNumbers` + `UpsertAutoNumber` + `generateAutoNumbers/Batch`; DROP 4 legacy tables via data-spec; remove legacy `Table*` constants | PR-1a | ~10 | ~2850 | D | Med |
| **F — Frontend: 3 LOC lock fix (PR-1a)** | Remove `'AutoNumberText__c'` from 3 Sets in `MetadataRecordForm.tsx:17-21` only | PR-1a | ~3 | 0 | post-D | Low |
| **F' — Full FE cleanup (PR-1b)** | `recordUtils.ts:54` + fixtures + `generated-schema.ts` + agent-browser evidence + console-warning guard (F18) | PR-1b | ~30 | ~20 | PR-1a merged | Low |
| **G — Data-spec skill** | `.agent/skills/data-spec-apply/SKILL.md` — `draft-rollback` skip + env transitions + `incident_ticket:` enforcement; applier code update | PR-1a | ~200 | 0 | parallel | Low |
| **H — Tests** | 17 unit + 13 integration + J1 fuzz (with determinism F12) + 19b mixed-bucket (F13) + partial-fail recovery (F14) + 三件套 | PR-1a (BE), PR-1b (FE) | ~1600 | 0 | paired with each lane | Med |
| **I — CI + generator** | Hook `platform_config_autonumber_formats.go` into Makefile `verify-generated` (F17); add canonicalizer grep-guard (F16) | PR-1a | ~40 | 0 | C1 | Low |
| **M — Metrics 埋点 only (PR-1a)** | Prometheus register + emit: `autonumber_quarantined_fields`, `autonumber_fallback_in_flight`, `autonumber_retry_attempts`, `autonumber_reservation_duration_ms` | PR-1a | ~30 | 0 | A | Low |
| **M' — Runbook + alerts (PR-1c, T+3d)** | `docs/runbooks/autonumber.md` + alert yaml per §11 Phase 2 | PR-1c | ~200 | 0 | PR-1a merged | Low |
| **N — LOC spike** | Throwaway `spike/autonumber-loc-measurement`; run rough diff; record in PR-1a desc | PR-0 | 0 | 0 | — | Low |

### 2.2 DAG (v2 — wave-by-wave)

```
PR-0: Lane N (LOC spike, throwaway)
          │
          ▼
PR-1a  Wave 1 (parallel):   A0-skeleton │ B-schema │ C1-format-seed │ G-skill │ H1-parser-tests │ H1-renderer-tests │ H1-canon-fuzz
PR-1a  Wave 2 (parallel):   A-engine-impl  │ C2-counter-seed (after A's parser)
PR-1a  Wave 3 (parallel):   H2-integration │ M-metrics-emission │ I-CI-hooks
PR-1a  Wave 4 (SERIAL):     D-wiring + E-legacy-deletion + F-3LOC-fix  ← single commit
PR-1a  Wave 5 (serial):     三件套 + backend runtime verify + 4-quadrant review
          │
          ▼ merge
PR-1b  (within 48 working hours): F' + H-FE-agent-browser (including console-warning guard)
          │
          ▼ merge
PR-1c  (within 3 days post-PR-1a): M' runbook + alert
```

**D moved out of Wave 3** to Wave 4 (v2 fix F20) — D+E are single-commit serial.

---

## 3. TDD Execution Order (v2)

### Tier 1 (no deps — parallel Wave 1)
1. H1-parser: tests 5, 5a, 5b, 6, 7, 14, 15
2. H1-renderer: tests 1, 2
3. H1-canonicalize: J1 fuzz — round-trip + **`canon(x) == canon(x)` determinism over 1000 inputs (F12)**

### Tier 2 (Wave 2 — depends on Tier 1)
4. H1-reserve-simple: test 17 (two-goroutine first-use race, scope=global pre-seeded)
5. **H1-reserve-missing-perday-legit**: test 17a (per_day new-day own-txn UPSERT → success) (F3)
6. **H1-reserve-missing-global-corruption**: test 17b (scope=global row DELETE → `ErrCounterMissing`, **NEGATIVE ASSERT** no UPSERT call on `global` path) (F3)
7. H1-overflow: test 6
8. H1-reserve-fallback: tests 21, 22, 22a — with `tidb_txn_mode='pessimistic'` precondition (F11)
9. H1-cross-record: tests 8, 8a, 8b, 9, 10, 11, 12, 13
10. H1-batch: test 19 (single-bucket) + **test 19b (10 mixed buckets, throughput ≥ 200/s) (F13)**

### Tier 3 (Wave 2+3 — seed + verify)
11. H1-seed-regex: FAIL-CLOSED unit
12. H2-seed-integration: tests 23, 23a, 23b, 24, 25, 26 — **includes F8 scope-aware GREATEST: legacy `_System_AutoNumber.CurrentNumber > live_today_max` resolves correctly**
13. **H2-seed-partial-fail-recovery** (new per F14): synthetic unparseable row mid-scan → abort → remove → re-apply → verify complete
14. H2-verify-gate: R1, R2 — V1–V6 with **F7 RecordTypeCode dual-check (`IS NOT NULL AND != ''`)**
15. H2-admin-bypass: ErrRuleQuarantined unit + **engine-init non-crash on parse fail (F9)**

### Tier 4 (Wave 4 — wiring)
16. H2-wiring: tests 18, 20, 28, 29
17. H3-三件套: idempotency × 3, concurrency × 3 parallel (`max_open_conns=10` per F19), multi-state (empty/pre-v2/post-cutover)
18. H3-backend-runtime: Account create → `IBG-B-<today>-003968`; Contract → `SG-CSA-<YYMMDD>-<NN>`

### Tier 5 (PR-1b)
19. H-FE-agent-browser: cases 30–34 + **`browser_console_messages` assert no hydration warnings (F18)**

**Concurrency tests (17, 17a, 18, 21, 22, 22a, 19b) run with `go test -race -count=20`.**

---

## 4. PR Split (v2 — confirmed 2-PR + follow-up runbook)

| PR | Branch | Scope | Est. LOC (add/del) | Gate |
|----|--------|-------|--------------------|------|
| PR-0 | `spike/autonumber-loc-measurement` | Lane N, throwaway | 0/0 | Abandon after LOC recorded |
| **PR-1a** | `feat/autonumber-v2-cutover` | A+B+C1+C2+D+E+F(3LOC)+G+H(BE)+I+M(emissions) | ~4400/~2850 | Full 4-quadrant review; 三件套; backend runtime verify |
| **PR-1b** | `feat/autonumber-v2-frontend-cleanup` | F' + H-FE-agent-browser | ~30/~20 | Dual-model review + agent-browser with console guard + grep-clean FE |
| **PR-1c** | `docs/autonumber-v2-runbook-alerts` | M' runbook + alerts | ~200/0 | Docs review only |

**Acceptance subsets:**
- PR-1a: §1.3 + §11 Phase 1 acceptance (backend); `IBG-B-<today>-003968` asserted; V1–V6 all green; 三件套 report posted; 48h FE lock-degradation window avoided via F fix
- PR-1b: FE grep-clean `AutoNumberText__c`; agent-browser transcripts + console-log-no-warnings evidence
- PR-1c: alerts active per §11 Phase 2 SLOs

---

## 5. Known Risks & Mitigations (v2 posted on PR-1a)

1. **§5.2 `reserveOne` first-use livelock** — NO `INSERT…ON DUPLICATE…Rollback()`. `global` pre-seeded (Approach X); `per_day` new-day own-txn UPSERT (Approach Y). Test 17b CORRUPTION assertion.
2. **§5.2 sample-once** — `assignedAt` sampled ONCE inside `BeginTx` BEFORE `sem.Acquire`. PRD §5.2 lines 497-533 verbatim.
3. **RecordTypeCode column semantics** — `VARCHAR(16) NULL`; V6 dual-check; seed uses UPDATE (F7).
4. **Admin-bypass verify** — raw-SQL UPDATE to `auto_number_format` → cache reload → re-parse → quarantine on fail (in-memory per F9).
5. **Rollback sequence** — git revert → deploy → spec apply staging → verify → spec apply prod; hard-documented in `docs/runbooks/autonumber.md` (F10).
6. **WARN-and-skip NEVER** — unparseable seed row aborts with structured error (field_id + row.Id + raw + regex).
7. **P1-R3-RT-ordering** — `SeedAutoNumberCounters` asserts `_System_RecordType` non-empty before `{RecordType.*}` format.
8. **Semaphore LRU** — `max(512, 4×|fields|)` cap + 48h TTL.
9. **Canonicalizer single-owner** — enforced by CI grep `json.Marshal(.*TokenRefs)` = 0 (F16).
10. **TiDB pessimistic** — engine forces `SET SESSION tidb_txn_mode='pessimistic'` on reservation+fallback conns (F11).
11. **Seed scope-aware GREATEST** — per-field scope map in seed data-spec; test 25/26 covers legacy-global > live-today edge (F8).
12. **Connection pool** — `max_open_conns=10` per apply process; Phase-0 checklist "no other consumers on branch" (F19).
13. **Quarantine non-crash** — in-memory, recomputed at init; parse fail logs + marks + continues (F9).
14. **Mixed-bucket batch** — test 19b guards throughput ≥ 200/s on 10 scope-keys (F13).
15. **Seed partial-fail recovery** — test in H2-seed-partial-fail-recovery (F14).

---

## 6. Open Questions (PRD §12.2) — User Signoff 2026-04-17

**Confirmed by user:**
- **Q1 null-policy = fail-closed** — null FK / null target / missing row → abort (no `"XX"` default). Per-token `literalEmpty` deferred to v2.1.
- **Q11 RecordTypeCode = Approach α** — new column `_System_RecordType.RecordTypeCode VARCHAR(16) NULL`; V6 dual-check.
- **Q12 readStrategy = caller_txn** — per-token `fresh_read` opt-in in `auto_number_token_refs`.

**Other §12.2 working defaults (fold into PR-1a description):**
- Q2 depth-2 `fkChains` syntax, Q3 verify-gate pinned binding, Q4 data-specs primary, Q5 max-width 18, Q6 UTC-only, Q7 1-month legacy soak, Q9 Phase-0 2h, Q10 per_day code-path only (no seeded field uses it at cutover)
- Q8 ops backup 2w retention — **open: confirm with ops owner before PR-1a**

**No blocking questions remain for coding start.**

---

## 7. Verification Plan

### 7.1 三件套 (post on PR-1a)

Test DB: `4Qbn3F3nyaU9DLk.root` (user confirmed). Pre-flight: `__pretest_bak_` snapshot of 4 legacy tables; `max_open_conns=10` per apply.

- **Idempotency (3×):** `go run ./backend/cmd/setup apply` → runs 2+3 <10% of run 1; counts identical; no PK duplicates
- **Concurrency (3× parallel):** all exit 0; exactly one wins outer `nexuscrm_bootstrap_mutation`; final state matches single-apply
- **Multi-state:** (a) empty DB → apply+verify green; (b) pre-v2 legacy → apply reads legacy + GREATEST + drops; (c) fully cut-over → apply no-op

### 7.2 Backend runtime verify

```bash
go run ./backend/cmd/server &
# auth as admin@test.com
# POST Account "Autonumber Test" BillingCountryCode=SG → assert Account_ID__c = IBG-B-<today>-003968
# POST Contract AccountId=^ RecordTypeId=ServicesAgreement → assert Name = SG-CSA-<YYMMDD>-<NN>
# POST Quote → depth-2 fallback
# go test -race -run TestConcurrentAccountInsert  # 100x100 torture
# paste logs to PR "Local Runtime Verification"
```

### 7.3 agent-browser (PR-1b)

```bash
pnpm --filter frontend dev &
agent-browser open "http://localhost:<port>/lightning/o/Account/new"
# fill, save, screenshot → evidence/autonumber-v2/account-create.png
# repeat Contract/Quote/Edit-locked/Form-post-cutover (cases 30–34)
agent-browser browser_console_messages > console.log
# MUST grep -E 'hydration|did not match' console.log = 0 hits (F18)
```

### 7.4 4-Quadrant review

All 4 triggers fire on PR-1a: schema + control-plane + concurrency + safety-regression. Force `/review "full review"`. Zero CRITICAL across V1/V2 Claude + V1/V2 Codex.

---

## 8. File path manifest (v2 — highlights changes)

**Create (PR-1a):**
- `backend/internal/features/automation/autonumber/{engine,parser,renderer,reserve,canonicalize,cross_record,quarantine,semaphore_cache,errors,metrics,bootstrap}.go` — last one exports `SeedFieldCounter` (F6)
- `backend/internal/bootstrap/autonumber_seed.go`
- `scripts/gen/autonumber_seeds.go`
- `backend/internal/controlplane/packs/platform_config_autonumber_formats.go` (generated — hooked into Makefile `verify-generated` F17)
- `data-specs/2026-04-18-autonumber-v2-seed.md` — includes **per-field scope-source map** (F8)
- `data-specs/2026-04-19-autonumber-v2-rollback.md` — `status: draft-rollback`
- (NOT in PR-1a per F15: `docs/runbooks/autonumber.md` — moves to PR-1c)

**Modify (PR-1a):**
- `backend/internal/bootstrap/system_tables.json` — `_System_RecordType.RecordTypeCode VARCHAR(16) NULL` (F7)
- `backend/internal/bootstrap/schema.go` — phase5 rewire + delete `ensureStandardAutoNumbers` + **V6 dual-check** (F7)
- `backend/internal/controlplane/packs/platform_config.go:82+329-435`
- `backend/internal/features/records/persistence_insert.go:139`
- `backend/internal/features/records/persistence_bulk_insert.go:319`
- `backend/internal/features/records/persistence_service.go:864-916` (delete)
- `backend/internal/features/metadata/field_create.go:192-204` — calls `autonumber.SeedFieldCounter(ctx, fieldID)` (F6)
- `backend/internal/application/services/service_manager_init.go:117-135`
- `backend/internal/domain/ports/repositories.go` (remove `UpsertAutoNumber`)
- `backend/internal/infrastructure/persistence/metadata_schema.go`
- `shared/pkg/constants/z_generated_*.go` (regen)
- `.agent/skills/data-spec-apply/SKILL.md`
- `Makefile` — hook `platform_config_autonumber_formats.go` into existing `verify-generated` target (F17)
- **`frontend/src/features/record/components/MetadataRecordForm.tsx:17-21`** — drop `'AutoNumberText__c'` from 3 Sets (F4, 3 LOC)
- `.github/workflows/*.yml` or existing CI — add `grep -rE 'json\.Marshal\([^)]*[Tt]okenRefs' backend/` must return 0 hits (F16)

**Delete (PR-1a):**
- `backend/internal/features/automation/compound_autonumber_listener{,_test}.go`
- `backend/internal/features/automation/identifier_engine{,_test,_integration_test,_regression_test,_template_test}.go`

**Modify (PR-1b):**
- `frontend/src/core/utils/recordUtils.ts:54`
- `frontend/src/core/utils/recordUtils.test.ts:98`
- `frontend/src/features/record/components/MetadataRecordForm.test.tsx` (fixtures — remove `AutoNumberText__c` references)
- `frontend/src/generated-schema.ts` (regen)

**Evidence (PR-1b):**
- `evidence/autonumber-v2/{account,contract,quote,edit-locked,form-post-cutover}.png` + `console-no-hydration.log`

**Create (PR-1c):**
- `docs/runbooks/autonumber.md` — includes hard rollback sequence (F10)
- `ops/alerts/autonumber.yaml`
