Immich walkthrough
The demo migrates a small photo picker across one real contract change. This page names the inputs, the break, the repair, and the open decision.
Steps marked In Bob IDE happen inside Bob IDE through /api-upgrade. All other commands run in your own shell. A shell sequence is not a Bob run.
Key terms
Fixture. A pinned spec or scenario file that tests serve instead of a live server. Example: the old and new Immich specs live unmodified under tests/fixtures/immich/.
Guard check. A verification check that protects behavior outside the fix. Example: smart and metadata search checks pass in every stage, so the repair cannot quietly break them.
Regression check. A named check that ties one fix to its failing test and its stub traffic. Example: the random picker check fails before the repair and passes after it.
Patched stage. The post-repair verification run that must pass with matching trace. Example: the random check passes after random search gains its own path.
Inputs
The old spec is Immich v1.116.2 and the new spec is Immich v1.117.0. Both are OpenAPI 3.0.0 documents. Unmodified copies live under tests/fixtures/immich/, with release commits and hashes in the NOTICE beside them. The Vimanam capture of the pair reports 27 required changes across 4 operations.
The consumer is a small Rust crate using blocking requests and typed JSON. It runs random, smart, and metadata search through one shared response parser and collects asset IDs for the picker. It reads the server address from the environment or a flag, so tests can point at the stub.
The published demo consumer lives at noemaforge/sethu-demo-picker.
The break
POST /search/random changes its success response from SearchResponseDto (with assets.items) to an array of AssetResponseDto. The operation switched its reference while the old component stayed in use by smart and metadata search, so the change carries an operation origin.
Against the new fixtures, the typed decode of the array into the old shape fails. The random picker test fails with its expected assertion message. The failure lands after the stub served, validated, and answered the new array response, which the request trace confirms.
The repair
The naive repair changes the shared parser to expect an array. Random search passes, and smart and metadata search break, because they still receive the old shape. The guard checks catch this in the patched stage.
The correct repair gives random search its own path and leaves the shared parser alone. The regression check and both guards then pass against the new fixtures.
The open decision
The old random search request sends page. The new contract drops paging for random search. The pinned server accepts the extra field and strips it, so the wire stays quiet while the meaning is gone.
The picker offers a next page of random assets, so pagination matters to it. The migration therefore keeps one decision_required item: drop paging, repeat calls with deduplication, or move stable paging to another endpoint. That item blocks readiness until a human decides.
Command sequence
Run this sequence from the consumer checkout. Keep the Sethu checkout beside it for fixtures.
Copy the pinned specs into the consumer checkout first:
cp /path/to/sethu/tests/fixtures/immich/old.json ./old.jsoncp /path/to/sethu/tests/fixtures/immich/new.json ./new.jsonThen run each step from the consumer checkout:
- Install the pack into the consumer:
Terminal window sethu install . - Capture the contract change:
Terminal window sethu init --repo . ./old.json ./new.json - List the required set:
Terminal window sethu changes - Read focused context for one change:
Terminal window sethu context <change-id> - In Bob IDE, trace usage and repair code through
/api-upgrade. - Freeze the harness before the repair starts:
Terminal window sethu verify --freeze - Run the checks against the stub after each repair step:
Terminal window sethu verify - Record each outcome with its evidence:
Terminal window sethu record <change-id> --outcome fixed_and_verified --evidence run:<run-id>/<check> - Check accounting and readiness:
Terminal window sethu check --require-ready - Generate the report:
Terminal window sethu report --out ./report
Expected files and evidence
| Path | What proves it |
|---|---|
.sethu/pairs/ | The copied spec pair for the attempt |
.sethu/ capture | The immutable Vimanam output, stored unchanged |
runs/ | JUnit XML plus the stub request trace per check |
.sethu/ ledger | One disposition with evidence per required change |
./report/ | Markdown and HTML built from validated state |
A green summary line alone proves nothing. Read the run artefacts, the JUnit XML, and the stub trace before trusting a claim.