55 of 85 role skill bindings pointed at skills that were never authored,
so 10 of 11 team templates bound a smaller context bundle than their role
prompts assumed. Three roles bound nothing at all (gpu.bench_engineer,
threejs.shader_author, threejs.perf_engineer) while their prompts described
procedures they had no way to read.
The loader comment at team_template_loader.rs:167 already diagnosed this —
snake_case slugs in TOML against kebab-case skill files — and it was
half-fixed: the kebab names were corrected, the snake_case ones left.
It was invisible because both existing tests assert authored ⊆ referenced
(30/30, green) and the second explicitly declines to check the other
direction. So the failing half was the half nobody asserted.
Resolved every name by one of three explicit choices:
- 23 skills authored where the role genuinely needed the procedure
(gpu, threejs, research, analysis, frontend, mobile, backend, platform)
- renames onto authored skills where one existed in substance, including
the four-near-duplicate cases that collapse onto one real skill
- 22 aspirational references deleted — a binding an agent cannot read is
a promise, not a capability
Two tests now hold it. The unit test checks referenced ⊆ authored against
the files. The new integration test runs both loaders in boot order and
asserts the bindings survive the trip through the database, which is a
different question: resolution goes through skills_catalog rows, so a skill
file that exists but fails to ingest still leaves the role empty.
Negative controls: the unit test failed naming all 55; the integration test
fails naming the exact role when one name is reverted.
threejs.shader_author and .perf_engineer gained a second and third skill
after the collapse — pin_in_context pins idx < 2, so a role left with one
skill silently pins less than the policy intends.
Co-Authored-By: Claude Opus 5 <[email protected]>
52 lines
2.3 KiB
Markdown
52 lines
2.3 KiB
Markdown
---
|
|
name: postgres-integration-testing
|
|
description: Testing against a real Postgres rather than a mock, with isolation that survives parallel runs.
|
|
when_to_use: You are the tester covering code that issues SQL.
|
|
tags: [backend, testing, postgres]
|
|
---
|
|
|
|
# Mock the network, never the database
|
|
|
|
A mocked database agrees with whatever the code believed. Constraints, cascades,
|
|
transaction visibility, type coercion and the SQL itself are exactly the things
|
|
that break, and a mock asserts none of them.
|
|
|
|
## Isolation is the whole problem
|
|
|
|
Parallel tests sharing a database interfere in ways that look like flaky code.
|
|
Three workable strategies:
|
|
|
|
1. **A fresh migrated database per test.** Cleanest and slowest. Right when the
|
|
suite is small or the schema is the thing under test.
|
|
2. **A transaction per test, rolled back.** Fast and well isolated, but the code
|
|
under test cannot manage its own transactions — which rules it out for
|
|
anything testing commit behaviour.
|
|
3. **Unique keys per test.** Every row keyed by a per-test uuid, no cleanup.
|
|
Scales well, and the leftover rows are useful when something fails.
|
|
|
|
Pick one per suite and say which. Mixing them produces the failures each was
|
|
meant to prevent.
|
|
|
|
## Test what only a real database can tell you
|
|
|
|
- **Constraints fire.** A unique violation, a FK failure, a check constraint —
|
|
assert the error, not just the happy path.
|
|
- **Cascades do what you think.** `ON DELETE CASCADE` reaching further than
|
|
intended is a data-loss bug that only a real delete reveals.
|
|
- **The migration applies to a populated table.** A migration tested on an empty
|
|
database has not been tested. Insert rows first, then migrate.
|
|
- **Concurrent claims are atomic.** For any `FOR UPDATE SKIP LOCKED` queue,
|
|
run two workers and assert the row was claimed once.
|
|
|
|
## Assert on the database, not only the return value
|
|
|
|
A handler can return 200 while writing nothing. Read the row back and check it.
|
|
The class of bug where the code "succeeded" and the data did not change is
|
|
invisible to a test that only inspects the response.
|
|
|
|
## Keep it fast enough to run
|
|
|
|
An integration suite nobody runs protects nothing. Share one container across
|
|
the suite rather than per test, run in parallel with proper isolation, and keep
|
|
fixtures small — realistic in shape, not in volume.
|