# Output of shift/run_migrate_demo.sh — 2026-10-15T03:57:55Z, gcc 13, cargo 1.97.0 (c980f4866 2026-06-30), OpenSSL 3.0.13
# (Temporary paths and timings vary per run.)

Stored permits (true dates): permit-F 2065-06-01, permit-G 2066-01-01. Clock: 2060-01-01.

== M1. Program on the 28-year shift reads its stored data: correct
  permit-F  expires=2065-06-01T00:00:00.000000000Z  valid   (1978 days left)
  permit-G  expires=2066-01-01T00:00:00.000000000Z  valid   (2192 days left)

== M2. Reconfigure to 56 years WITHOUT migrating the stored data: every stored date is now 28 years wrong
  permit-F  expires=2093-06-01T00:00:00.000000000Z  valid   (12205 days left)
  permit-G  expires=2094-01-01T00:00:00.000000000Z  valid   (12419 days left)

== M3. Migration without confirming the program is stopped: refused
  migrate: refusing: stop the program and its data feeds first (shutter), then pass --confirm-program-stopped

== M4. Proper procedure: SHUTTER (stop), MIGRATE + RECONFIG (one step), restart
  migrate: DONE - 2 file(s) moved from shift 883612800 to 1767225600; config updated; backups kept; receipts in /tmp/tmp.znAsKD3XKF/a/journal/receipts.log
  config now: shift_secs=1767225600
  backups kept: 2
  receipt fingerprint matches coreutils sha256sum: yes
  permit-F  expires=2065-06-01T00:00:00.000000000Z  valid   (1978 days left)
  permit-G  expires=2066-01-01T00:00:00.000000000Z  valid   (2192 days left)

== M5. Someone restores the old config and runs the migration again: refused (would shift twice)
  migrate: /tmp/tmp.znAsKD3XKF/a/permits.db was already migrated (receipt: 1792036676 from=883612800 to=1767225600 before=11006b419d74567acd5ae7207ee6901d4fd114c1b0d4c863a4ad0821fd7e2483 after=bd395737f08652801465777ee6e74da24faa3793b5c72e879d8a135a796a7e76 file=/tmp/tmp.znAsKD3XKF/a/permits.db); refusing to shift it twice

== M5b. Same, but the program has written to its file since the migration (contents changed).
   The fingerprint no longer matches, so the history-vs-config check must catch it.
  migrate: /tmp/tmp.znAsKD3XKF/a/permits.db: migration history says this file is on shift 1767225600, but the config says 883612800; the config may have been restored from an old copy. Refusing until they agree (receipt: 1792036676 from=883612800 to=1767225600 before=11006b419d74567acd5ae7207ee6901d4fd114c1b0d4c863a4ad0821fd7e2483 after=bd395737f08652801465777ee6e74da24faa3793b5c72e879d8a135a796a7e76 file=/tmp/tmp.znAsKD3XKF/a/permits.db)

== M6. Migration interrupted halfway (first file replaced, second not, config unchanged)
  migrate: TEST CRASH at 'mid-replace' (simulated interruption)
  state after crash: config=shift_secs=883612800, journal present: yes
  run the same command again:
  migrate: found an interrupted migration; finishing it instead of starting a new one
  migrate: RECOVERED - finished interrupted migration 883612800 -> 1767225600 for 2 file(s); config updated
  config now: shift_secs=1767225600
  permit-F  expires=2065-06-01T00:00:00.000000000Z  valid   (1978 days left)
  permit-G  expires=2066-01-01T00:00:00.000000000Z  valid   (2192 days left)

== M7. Stored data includes a 1950 date. It fits the 28-year window (1929-2066) but not the
   56-year window (1957-2094). Migration must refuse and change nothing.
  migrate: SHUTTER - 1 timestamp(s) cannot be migrated; nothing was changed:
  /tmp/tmp.znAsKD3XKF/c/permits.db: line 3: @T-1514764800: true time -631152000 cannot be moved into the new window
  data and config unchanged: yes
