OPS-010
The delta release hazard
A delta ships only changed files. If a changed file calls something introduced two releases ago that the operator never deployed, the site fatals on every page.
Shipping only the files that changed is efficient and introduces one specific failure: the delta assumes everything before it is already on the server. When a release was skipped, a file in your delta calls a function that does not exist there, and the error is a fatal on every page because the dependency is usually a shared header.
It is easy to miss in testing because your own tree is complete. The operator's is not.
Two defences, and they are complementary. Guard calls to anything introduced recently with function_exists, so a missing dependency degrades instead of dying. And when a delta's changed file depends on an earlier release, re-ship that earlier file with it — the cost is a few kilobytes.
<?php
// templates/header.php — shipped in this delta.
// count_open_tickets() arrived in an earlier release. If the operator skipped
// it, an unguarded call here fatals on EVERY page of the site.
$supportBadge = 0;
if (function_exists('count_open_tickets')) {
$supportBadge = count_open_tickets();
}
?>
<a href="support.php">
Support<?= $supportBadge > 0 ? ' <span class="badge">' . (int) $supportBadge . '</span>' : '' ?>
</a>
<?php
// A release script that lists what each delta depends on, so the dependency
// files get re-shipped rather than assumed.
//
// deltas/1.4.1/manifest.php
return [
'files' => [
'templates/header.php',
'includes/exchange.php',
],
// Introduced in 0.35, required by the header above. Re-shipped because we
// cannot prove the target server has it.
'carry_forward' => [
'includes/support.php',
'bootstrap.php',
'migrations/031_support.sql',
],
];
Using it
Keep a version marker in the database and print it in admin. Comparing it to the release you are about to apply tells you whether a delta is safe.
Prefer a full package for a major version, deltas in between. That bounds how far a skipped release can propagate.
When in doubt, re-ship. Bandwidth is cheaper than a dead site.
What bites people
function_exists guards are a safety net, not a design. Too many of them and you cannot tell which version the code is written for.
A delta that includes a migration but not the code that uses it is the same hazard in reverse: harmless, but the feature silently does nothing.
Deleted files are invisible in a delta. If a release removes something, say so in the notes — the operator has to delete it by hand.
This one touches real money. Point it at a throwaway wallet and watch a full cycle before you trust it with a live balance.