# Pattern update testing Two CI gates stand between an incompatible pattern and every piece running it. This document specifies what each one proves, what it deliberately does not, and what an author does to participate. ## Why the gates exist The automatic pattern updater performs **no structural check at all**. `cf piece setsrc` refuses an incompatible replacement by calling `assertPatternSchemasBackwardCompatible`, but the automatic path compiles the new source, verifies the entry identity, and applies it. So CI is the only thing standing between an incompatible pattern and a running piece, and a bad update does not throw — it leaves a piece that can no longer materialize. The two gates guard different halves of the same risk: | | Gate | Test topology suite | What it proves | | --- | --- | --- | --- | | Tier 1 | `deno task pattern-compat` | `pattern-compat` | The **contract** a pattern declares can still be applied over every contract it has declared before | | Tier 2 | `deno task pattern-vintage` | `pattern-vintage` | A real **document** written by an older version is still readable, and its data survives | Tier 1 is a statement about schemas. Tier 2 proves the stronger thing schemas cannot say. Neither subsumes the other: a contract can stay compatible while the data goes unreachable, and a fixture can only cover patterns some test actually instantiates. ## Tier 1 — contract compatibility Compiles **every** authored pattern under `packages/patterns/`, derives its argument and result schemas, and proves the current contract can be applied over every contract recorded for it under `packages/patterns/baselines/`. There is no opt-in: a pattern is covered by existing. Baselines are **append-only**, enforced mechanically by `tasks/check-baselines-append-only.ts`, which the test topology's `repo-history-gates` suite runs. An author-run `--update` that could remove a baseline could remove the very one that would have caught a break. A break the repository decides to ship is declared instead, in `tasks/pattern-compat-accepted-breaks.ts` — see the finding it answers below. ### Findings and their remedies - **`contract is not recorded`** — the pattern's contract changed and the new one has no baseline. Run `deno task pattern-compat --update` and commit the recorded baseline. Routine. - **`cannot be applied over baseline