Counts and totals can match while individual records are wrong. The capstone compares canonical rows by identity, including owner relationship, title, boolean state, exact cents and timestamp. It reports missing, unexpected and changed IDs in stable order.
Then run the real adapters. Python creates and queries SQLite; Go uses maintained pgx to migrate/import/query PostgreSQL; psql independently checks the final row count. The output distinguishes full-row reconciliation from additional migration, constraint, transaction and lifetime evidence.
The source SQLite database is built from fixtures/source.sql in the new owned directory, then read back into typed JSON. Go validates and inserts those actual rows in a transaction. ReadNotes scans typed PostgreSQL results, normalizes UTC formatting and compares the complete records.
After reconciliation, the lab verifies quoted names, a rejected injection-shaped value, generated identity, foreign keys, cents checks, atomic writes, checksum drift, failed-DDL rollback and query cancellation. A canceled query is followed by a successful pool ping. These observations concern the supplied local application, not production readiness.
package main
import ("fmt";"reflect")
func main(){
a:=map[int]int{7:29,42:71};b:=map[int]int{7:71,42:29};fmt.Println(len(a)==len(b),a[7]+a[42]==b[7]+b[42],reflect.DeepEqual(a,b))
}A full-row comparator distinguishes identity mismatch from field mismatch. Duplicate IDs are invalid input, not an instruction to silently keep the last row. Target rows must already be canonical; otherwise the comparison would hide a target-side normalization defect.
The download includes complete source, versioned SQL, public contract tests, deterministic fixtures, starter and cleanup instructions. Its server is local-only, freshly owned and stopped before removal. The hosted tasks remain pure standard-library Go, preserving the playground’s offline boundary.
package main
import ("fmt";"sort")
func main(){
ids:=[]int{42,7,1};sort.Ints(ids);fmt.Println(ids)
}Run go mod download, go test ./... and python3 -B lab.py in the extracted lab. Inspect the complete JSON report, actual target types, full-row reconciliation and psql assertion. The launcher stops and removes only its owned fixture cluster; it never reuses a server or touches learner progress.
Read the known limits: the fixture uses whole-second timestamps, bounded imported IDs/cents and a small local application role. Future production work needs its own authentication, backup, deployment, migration and operating plan.
Download the complete PostgreSQL migration lab: Go/pgx application, isolated PostgreSQL launcher, actual SQLite fixtures, starter, tests and run/cleanup instructions.
The records survive the database boundary.
This snapshot came from the owned local lab. Choose an imported identity to inspect its actual source and canonical target. Reconciliation covers all fields, before a separate successful application write brings the final note count to four.
- 1 · Schemaowners · notes · events
- 2 · Indexowner lookup
- Reapplyzero pending versions
- Bad version 3DDL/history rolled back
SQLite source · ID 1
{
"id": 1,
"owner_id": 1,
"title": " first note ",
"done": 0,
"cents": 29,
"created_at": "2024-01-01T01:00:00+01:00"
}PostgreSQL canonical row
{
"id": 1,
"owner_id": 1,
"title": "first note",
"done": false,
"cents": 29,
"created_at": "2024-01-01T00:00:00Z"
}done → booleancents → bigintcreated_at → timestamp with time zone3 source rows · 3 target rows · no missing, unexpected or changed identities
Inspect the separate database checks
- Quoted owner name
- 2 matching rows with a bound parameter
- Injection-shaped name
- 0 matches · value remains data
- Next generated identity
- 43 after imported maximum 42
- Failed note/event transaction
- Partial note write rolled back
- Foreign key and cents constraints
- Actual invalid inserts rejected
- Canceled query
- Cancellation observed; pool usable afterward
- Application role
- Nonsuperuser · pool maximum two connections
- Owned cleanup
- Cluster stop confirmed; fixture directory removed