Skip to main content
ClaudeWave
Skill909 estrellas del repoactualizado today

add-migration

>

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/Pipelex/pipelex /tmp/add-migration && cp -r /tmp/add-migration/.claude/skills/add-migration ~/.claude/skills/add-migration
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Add a Migration Entry

A configuration **surface** — `pipelex.toml` and its tiers, `telemetry.toml`,
`pipelex_service.toml`, the inference backend definitions in
`inference/backends/` — ships a checked-in ledger at
`pipelex/migration/ledgers/<surface-id>.toml` recording, as data, every shape
change it has ever undergone. A user's existing file is repaired by replaying that
ledger over it, so a schema change with no entry is a schema change that breaks
every machine in the field.

`docs/migration-ledger.md` is the normative contract. **Read it before writing an
entry** — this skill is the procedure, that document is the law, and where the two
disagree the contract wins.

## The one rule

**Derive the entry from the gate's refusal, never from memory.** The coverage
check recomputes the surface's fingerprint and names every path, every enumerated
spelling and every value domain the change moved. That output is the fingerprint
diff, already rendered. Composing an entry by hand from your own reading of the
diff is how a rename gets misspelled and every user's file is migrated onto a key
the schema rejects, with the tool reporting success.

## Step 1: See what the gate says

`make check-migration-schemas` (alias `cmig`) is deliberately **not** in
`make agent-check` — it is a golden check, and a fail-regenerate-fail cycle in the
loop agents run constantly is how a gate goes permanently green while catching
nothing. So run both gates explicitly:

```bash
make cl      # check-ledger: is the ledger legal, and is replaying it harmless?
make cmig    # check-migration-schemas: is every schema change accounted for?
```

Each failure names the surface and a `kind`, and every message says what to do. The table below is not the whole list of kinds — it is the map of which ones mean **an entry is owed**, and what it owes:

| Kind | What the change did | What the entry owes |
|---|---|---|
| `removal_needs_a_bump` | a path, an enumerated spelling or a value domain is gone from the models but still in the head golden | a version bump plus the operation that removes or repairs it |
| `unaccounted_path` | a path the diff removed that no operation in the entry acts on | an operation naming that path |
| `enum_member_not_remapped` | an enumerated spelling disappeared | a `remap_value` from the old spelling to the new one |
| `value_domain_narrowed` | the type or a bound got stricter — nothing was removed, but a legal value stopped being legal | a `remap_value` per narrowed path, or an `unsafe` entry naming them in `declared_narrowed_paths` |
| `dead_op` | an operation whose source no schema version ever removed, or a `delete_table` pointed at a key | fix the path or the kind — the applier would skip it forever while looking like an accounting |
| `destination_occupied` / `destination_not_in_new_shape` | an operation's destination is wrong | fix the destination — this is usually a typo, and it is the defect the transform goldens exist to catch |
| `over_deletion` | the entry removes a path the schema still has | narrow the operation; a parent is deleted only when the parent itself retires |
| `required_path_without_default` | an added required path has no value in the defaults layer | give it a default — an added key is absorbable only because the defaults layer carries it |
| `snapshot_pending` / `fingerprint_drifted` | the goldens predate the models | usually just step 5; if it is the only failure, no entry is owed |
| `reserved_path_reused` / `reserved_value_reused` | the new name was retired by an earlier version | **pick another name** — see step 4 |
| `convergence_broken` | replaying the ledger over a healthy reference document is not a no-op | the operation acts on live material, or on the wrong path |

**A gate that only asks for a regeneration is not asking for an entry.** An
additive change — a new optional key, a widened type, a relaxed bound — costs a
`make umig` and nothing else. Stop at step 5 in that case.

## Step 2: Decide the safety

`safety` governs whether the applier may act, and it is not a matter of taste:

- **`safe`** — the operations mechanically complete the repair. The file is
  rewritten after one confirmation. Everything structural is safe: renames, moves,
  deletions, and a `remap_value` whose old spelling is genuinely no longer legal.
- **`unsafe`** — no operation in the vocabulary can repair the file, so the entry
  is *reported and never applied*. This is the form for a tightened numeric bound,
  a completeness rule a validator expresses, anything where the tool would have to
  choose a value on the user's behalf.

An `unsafe` entry may legitimately carry no operations at all — and then
`declared_narrowed_paths` is **mandatory**, because the engine questions a
document before reporting an entry, and an entry with neither operations nor a
declaration answers "nothing to say" for every file there will ever be. The
declaration is spelled as the fingerprint at the entry's own version records the
paths, `*` segments included, and `make cl` refuses a path that version does not
have.

`guidance` is independent of `safety`: any entry may carry it, and it is the
explanation a person reads, **never the mechanism**. Anything expressible as
operations must be operations.

## Step 3: Write the entry

Two edits to `pipelex/migration/ledgers/<surface-id>.toml`, in one change:

1. In `[surface]`, raise `current_schema_version` to N.
2. Append a `[[migration]]` block. Entries are contiguous and named for their
   version — the id **must** be `<surface-id>@<N>` and `to_schema_version` **must**
   be N, or the file is refused when it is parsed.

```toml
[[migration]]
id                = "example-config@2"
to_schema_version = 2
introduced_in     = "0.46.0"
breaking          = true
safety            = "safe"
title             = "Short imperative summary of the shape change"
description       = "One or two sentences a release note can quote."
guidance          = """
What a user should understand o