JGNT jgnt@juggernaut.work:~$
--lang=ru
$ cd ..
2026-09-26 · 2 min · #migration #process #laravel

Rule zero: how a photo archive moved one photograph at a time

One object, check it with your eyes, then ten, then the background. A boring rule — and what it found while moving sniff.ru.

Why a rule

A bulk migration does not break on the thousandth record. It breaks on the first; it is just expensive by the thousandth. So none of our commands does «everything» by default: first one record, and a person looks at the result.

[NOTE] Rule zero is not about tests. Tests check the code. The rule checks the result: by eye, the way a person will see it.

Four steps

  1. One object. Run it, open it, look.
  2. Ten. Check them by hand.
  3. Twenty — by eye again.
  4. Only then the background: a job that takes one record at a time and leaves a trace on it.

For the sniff.ru photographs it looks like this:

$ ship remote artisan media:one        # one photograph, in the foreground, with the result
$ ship remote artisan media:queue --limit=20
$ ship remote artisan media:status     # how far it has got

What ten found

On ten files the EXIF reader came back «read» seven times — and seven times all it held was a width and a height written by an old resizer, not by the camera. The log line said it worked. On a thousand we would not have noticed.

The first ten jobs on the server failed with «source missing»: the worker in the server's compose had no mount for the archive. Ten failed jobs are one line of config. Thirty-three thousand are an evening of cleaning up.

The result

galleries             535
photos              33346
offloaded           33345  (100%)
failed                  1
still on local disk     0

One photograph did not move, and it shows in the status — rather than being lost somewhere in the middle of a batch.

The same for AI agents

We give an agent a plan in a file, not a task: one object, a report, a human check, then ten. A chat forgets; a plan file does not.