The repository had accumulated application code, operational scripts, and local tooling over time. The move was meant to reduce that coupling. Our migration plan covered the files inside the repository. It did not cover the automation and service definitions that lived outside it, which had been set up gradually and had drifted outside the visible project boundary.

That is where the audit began, with an inventory of scheduled tasks, service definitions, deployment settings, containers, credentials, and any other runtime reference that could still point to the old location.

What the inventory found

It turned up scheduled tasks and enabled service definitions that still referenced the old location. It also turned up retired processes and containers with no clear operational purpose left.

Some of those entries had not failed visibly, because the condition that starts or restarts them had not occurred yet. “Enabled” described configuration intent. It was never a successful end-to-end run. A later restart could have exposed the problem at an inconvenient moment. What we had found was an unverified dependency outside the migration plan, which is quieter than a dramatic failure.

That alone would have justified the migration. The worse one was in what the dead crons had been trying to do.

The backup that hadn’t run in three weeks

The most consequential finding was a backup job. We assumed recent recovery artifacts existed. When we inspected them, the latest successful artifact was much older than the intended schedule.

The scheduler entry was there. A runtime dependency had failed, and the error went only to a log that had no alerting and no regular review. The job counted as scheduled, and it never met its real purpose, which is producing a usable, recent backup.

A second scheduled task had the same shape. It kept invoking on its cadence while a required dependency was unavailable, and it produced repeated errors instead of the expected output. This says nothing against one scheduler in particular. Any job needs output verification and a failure path someone can act on.

Why this can sit forever

A silent backup failure is dangerous at any size. In a smaller operation it is easy for a missed artifact to have no visible owner and no routine review, so the first signal may arrive only when you need to recover.

Without the migration audit, these dependencies would have stayed configured and unverified. The corrective action was to define what a successful artifact looks like, who reviews it, how freshness is checked, and how recovery is tested. A new status screen would not have done that for us.

Use the substrate move as the audit

A rename, a host migration, a database move, a framework upgrade. Anything that touches the ground your system stands on forces you to enumerate what is standing on it. You have to find every reference to the old thing. That enumeration is an audit of your operational surface, and it costs almost nothing extra because the migration makes you do the walk anyway. The trap is treating the move as purely mechanical: patch the references, ship it, done. The value is in reading what you find while you are in there.

For a substrate move, we now capture a protected, access-controlled inventory before changing anything. It lists the relevant scheduled tasks, service definitions, container state, deployment configuration, ownership, expected outputs, and recovery dependencies. Secrets and identity-bearing files are handled separately under the organization’s credential policy, because an inventory should never become a reason to copy sensitive material into an unprotected archive.

The inventory makes the operational surface reviewable. You cannot validate a dependency you have not identified, and a migration is one of the rare moments when the full dependency walk is already required.

Status is not outcome

A scheduler may show a job as configured or invoked. A process may show as active. Neither observation proves the intended artifact exists, is fresh, is valid, and can be used for recovery.

So verify the outcome that matters. For a backup, inspect recency and run a controlled restore test. For a service, test the authorized endpoint and the expected behavior. For a scheduled data job, check its expected output and freshness. Pair each of those checks with alerting, an owner, and documented response steps.

The repository move took longer than a find-and-replace. It also turned a hidden operational assumption into a dependency and recovery practice we can audit.

If you are about to move a system, inventory every scheduled task, service and backup first, and check each one by its result. Then ask who confirms that your backups are recent and restorable, and how often.