# Day-3 Phase B0 — Pre-flight FK verify on prod (2026-05-12)

**Branch:** `day3-content-migration`. **Read-only prod queries only.**
Halt status: **CLEAN — no FK gaps. Proceed to Phase B.**

## TL;DR

Every FK target the migration will reference on the prod side already
exists. Specifically: 3 difficulty rows, 1 type row, 2 admin users, the
2 needed public fields (Measurement, Geometry), and the 2 needed levels
(400/Year 4 and 500/Year 5). Track-context bridge resolved all 5
ambiguous skills cleanly.

## Scope reduction from excluded stale tracks (47, 49, 55, 65)

| layer | before | after exclusion | dropped |
|---|---:|---:|---:|
| questions | 168 | **167** | 1 |
| skills (all in scope) | 168 | 167 | 1 |
| missing skills (needing insert) | 29 | **28** | 1 |
| missing tracks (needing insert) | 7 | **3** | 4 |
| pivots (in scope) | 168 | 162 | 6 |

The 3 surviving missing tracks:
```
track 42 "Area and Perimeter Year 4"   field_id=38(local)/32(prod)  level_id=5  user_id=1  status_id=3
track 44 "Rectangle and Square"        field_id=39(local)/33(prod)  level_id=5  user_id=1  status_id=3
track 59 "Triangles"                   field_id=39(local)/33(prod)  level_id=6  user_id=1  status_id=3
```

## Ambig-skill resolution via track-context bridge

All 5 ambiguous skills resolved cleanly — each had exactly one prod
candidate whose prod skill_track rows intersected with the local
skill's expected prod tracks:

| local_skill_id | candidates (prod) | winner | note |
|---:|---|---:|---|
| 77 (equivalent fractions) | [77, 377] | **77** | clean bridge |
| 106 (reading and writing numbers in numerals and in words) | [30, 106] | **106** | clean bridge |
| 107 (comparing and ordering numbers) | [31, 107] | **107** | clean bridge |
| 132 (rounding off answers to a specified degree of accuracy) | [132, 168] | **132** | clean bridge |
| 168 (rounding off answers to a specified degree of accuracy) | [132, 168] | **168** | clean bridge |

These are now treated as EXISTS_ON_PROD with the resolved prod_id —
they will NOT enter the insert set in Phase B.

Saved: `ops/dep-scope/ambig-resolved.json`.

## FK targets verified on prod (raw output)

### difficulties
```
id  difficulty
1   1
2   2
3   3
```
All 3 referenced by the 167 questions exist on prod. ✓

### types
```
id  type
1   MCQ
```
Single type (MCQ) referenced by all 167 questions; exists on prod. ✓

### users
```
id  email
1   info.all-gifted@gmail.com
2   pamelaliusm@gmail.com
```
The 2 admin user_ids referenced across questions/tracks/skills both
exist on prod. ✓

### fields (only the 2 needed for new track inserts)
```
id  field                         status_id
32  Measurement                   3
33  Geometry & Spatial Reasoning  3
```
Both public. ✓

### levels (only the 2 needed for new track inserts)
```
id  level  description
5   400    Primary/Grade/Year 4
6   500    Primary/Grade/Year 5
```
Both exist. ✓

## Final insertion plan (locked for Phase B)

| layer | row inserts | notes |
|---|---:|---|
| L1 levels | **0** | all referenced levels exist on prod |
| L2 tracks | **3** | 42, 44, 59 — stale 4 already excluded |
| L3 skills | **28** | 5 ambig resolved out of the insert set, 1 dropped via stale-track exclusion |
| L4 skill_track | **~37** | 162 in scope − ~125 already exist; finalised during Phase B as IDs allocate |
| L5 questions | **167** | 1 dropped via stale-track exclusion |
| **min total** | **≈235 rows** | reduced from 247 |

Plus the **64 tag-only UPDATEs** from yesterday's `tag_diagnostic_questions_on_prod`
draft, merged into the same migration per Pam's spec.

## Decisions still applying

- ✓ Stale tracks 47/49/55/65 excluded
- ✓ Ambig skills resolved via track context (all 5 → clean prod_id)
- ✓ Skill typos deferred to post-beta follow-up
- ✓ One-shot migration (γ) in dependency order inside `DB::transaction`
- ✓ 12 ambiguous questions NOT included in this migration

## Halt

Phase B0 complete. No FK gaps. Holding for Pam's sign-off before
drafting the Phase B migration file.

If Pam wants to verify the FK report independently, the verify SQL is at
`ops/.tmp-preflight.sql` (regenerable from this report — it's plain
SELECTs against difficulties, types, users, fields, levels).
