# Migrations-free grouped review contracts over legacy tables

Use this pattern when a sensitive dashboard needs a central review view over existing mappings without changing schema.

## Contract construction

1. Read existing source, mapping, queue, rule/alias, action-log, and specialist-review tables only. Never bootstrap schema from the read path.
2. Separate strict grouping identity from legacy lookup normalization. A safe label identity uses Unicode NFC, `casefold()`, and whitespace collapse while preserving punctuation.
3. Keep the old aggressive normalizer as an explicitly named compatibility function. Use it only for legacy queue/worker validation and collision detection. If several strict identities collapse to one legacy identity, keep them separate and mark each conflicted.
4. Derive opaque public keys from a domain-separated SHA-256 preimage. Truncate only when the contract explicitly requires it.
5. Load every strict group; do not inherit a queue/UI row limit. Test beyond the known production cardinality.
6. Release a recommendation only when an existing queue suggestion's canonical and score match a local rule, or an exact local alias/canonical rule matches. Recommendation is never confirmation.
7. Confirm only when every current target row has one consistent, nonempty canonical and valid score. Confidence remains separate; low confidence does not change review status.
8. Derive state from current mappings plus the latest matching action. Give collisions and current-data conflicts precedence over stale actions.
9. Hash an immutable sorted target set into a full domain-separated SHA-256 revision. Include stable item hash, day, and all mutable current mapping fields. Expose target row/day counts so Preview and Confirm can compare revision and cardinality fail-closed.
10. Return only bounded examples, days, counts, mapping/recommendation, state, confidence, opaque key, and revision. Do not expose row IDs, source IDs, raw payloads, filenames, or paths.

## Concurrent writer compatibility

A new central contract may be imported by concurrently developed writers before focused tests reveal that dependency.

- Recheck the current working tree and current imports/call sites, not only the base commit.
- Preserve required public compatibility helpers, such as the exact legacy aggressive normalizer.
- Make `resolve_group(connection, key)` return current revision and target counts without raw IDs.
- If unrelated edits appear after an initially clean status, treat them as concurrent work: do not revert or claim them, but verify that the new module still imports through those callers.

## Verification

- Use synthetic in-memory SQLite fixtures with no sensitive data.
- Cover strict Unicode grouping, punctuation separation, legacy collision failure, recommendation versus confirmation, confidence independence, revision change after target mutation, summary/open counts, and recursive absence of IDs/paths.
- Compare `connection.total_changes` immediately before and after contract calls to prove no writes.
- Compile/import the module and current writers that import it.
- Run focused tests first. Missing optional dependencies in an adjacent suite are environment evidence, not grounds to weaken a focused contract.