# The patch lifecycle

This is the one topic worth reading carefully. When two patches touch the same asset, the order they run in decides the result. PatchManager makes that order explicit, but the model has two layers. Once you understand passes and buckets, ordering is easy as a few function calls.

## Two layers: passes and buckets

Every patch runs in a **pass** and, within that pass, in an **ordering bucket**.

There are three passes, and they run in this order:


1. **Early**
2. **Default**
3. **Late**

There are three buckets, and within a single pass they run in this order:


1. **First**
2. **Default**
3. **Last**

You select the pass with `:Early()` or `:Late()` (or neither, for Default). You select the bucket with `:First()` or `:Last()` (or neither, for Default). So `:Early():First()` means "the first bucket of the early pass," which is as close to the front of the line as a patch can get.

**Most patches should set neither.** If you call neither, your patch ends up in the Default pass, Default bucket, and that is the right place for the large majority of edits. Leaving your patch in Default lets other patches order around it and keeps you out of the scramble for the front of the line.

Many of the example patches in these docs come from Redux's own source, and there they almost all carry `:Early():First()`. The docs leave it off, because it is not a template to copy. Redux uses it because it is the base overhaul: it specifically wants to establish a corrected baseline before any other mod looks at an asset, so it claims the very front on purpose. That is the right call for the foundation everyone else builds on, and the wrong call for a normal patch, where claiming the front means fighting to be first instead of cooperating with the normal order. If a patch of yours truly must run early, it is usually best to make it run after Redux with [`:After("Ksp2Redux")`](/doc/dependencies-and-ordering-werp1yYh7P) rather than racing it to the front.

## What a pass actually is

A pass is a full sweep over every label that has patches. The Early pass runs across all labels, then the Default pass runs across all labels, then the Late pass runs across all labels.

Passes are **not** per-asset, they are global. The early pass finishes for the entire game before the default pass starts. The asset's value carries over between passes, so a Late patch sees anything the Early and Default patches left behind.

## Carrying data from one label to another

This global ordering enables something you cannot do any other way: reading data from one label to affect data in a different label. Because a pass is a complete sweep over every label, and an earlier pass fully finishes before a later one begins, anything an early-pass patch observes is available to a later-pass patch, even when the two patches target different labels.

Within a single pass you cannot rely on this. The sweep visits every label, but you do not control which label it reaches first, and before/after only orders patches against each other within one bucket of one label. So to move information across labels, you split the work across passes: record in the earlier pass, apply in the later one. You stash what you read in a plain Lua variable at the top of your script and read it back in the later patch.

```lua
-- A table that lives for the whole run, filled in the Early pass.
local heavyParts = {}

-- Early pass: sweep the parts label and record what we care about.
PM.Parts:Patch("RecordHeavyParts")
        :Early()
        :Do(function(part)
            if part.mass and part.mass > 5.0 then
                heavyParts[part.partName] = true
            end
        end)

-- Default pass: a different label, using what the Early pass recorded.
-- Every part was already swept in Early, so heavyParts is complete here.
PM.Science:PatchTechNodes("AdjustForHeavyParts")
          :Do(function(node)
              -- ... consult heavyParts to decide what to change ...
          end)
```

The guarantee is only sound because the record patch is in an earlier pass than the apply patch. If both were in the same pass, the parts label might be swept after the tech-node label, and `heavyParts` would still be empty when the tech-node patch ran. This is the main case where using passes is genuinely necessary to make your patch work correctly.

Your script runs one time, at boot. But PatchManager runs the passes one time for each [feature set](/doc/features-geboWdIiDN) that it patches for. Thus a top-level table keeps its contents through all runs. Empty the table at the start of each run with `PM:OnBeginRun`. If you do not, a later set sees the records from the parts of an earlier set:

```lua
PM:OnBeginRun(function(set)
    heavyParts = {}
end)
```

```
Early pass    sweep every label   First -> Default -> Last
Default pass  sweep every label   First -> Default -> Last
Late pass     sweep every label   First -> Default -> Last
```

So the full order any single asset experiences is:

```
Early/First -> Early/Default -> Early/Last
  -> Default/First -> Default/Default -> Default/Last
  -> Late/First -> Late/Default -> Late/Last
```

with your finer ordering (next section) deciding the order *inside* each of those nine slots.

## Ordering inside a bucket

Within one bucket of one pass, patches are sorted by the before and after relationships you declare: `:Before`, `:After`, `:BeforePatch`, `:AfterPatch`. See [Dependencies and ordering](/doc/dependencies-and-ordering-werp1yYh7P). PatchManager topologically sorts the bucket so your "run after X" requests are honored.

## The trap: before and after do not cross buckets


:::info
`:Before` and `:After` only order patches within the same bucket of the same pass. Across different buckets, the relationship is silently ignored.

:::

If your patch is in the Default bucket and you say `:After("someones-first-patch")` but that patch is in the First bucket, the request does nothing. It will not error, because the buckets already sort relative to each other (First always before Default) and PatchManager will not let a finer rule contradict the coarser one.

The practical rule: put patches that need to be ordered relative to each other in the same bucket, then use `:Before` and `:After` between them. Use the buckets and passes for coarse separation, and before/after for fine ordering within a group.

## Why this design

The passes give mods a shared, predictable timeline without everyone having to know about everyone else. "Fixes go early, my big rework goes in default, cosmetic touch-ups go late" is a convention the whole ecosystem can follow. Two mods that have never heard of each other still end up in a reasonable order, and when they do need to coordinate, patch manager provides finer tools to handle that.

## What this means for you

A good way to think about the three passes in your own mod is by role:

* **Early: collect.** Use the early pass for patches that read and record data, like the `RecordHeavyParts` example above. Gathering happens first so the rest of your mod can rely on it.
* **Default: patch.** Use the default pass (set no pass at all) for ordinary edits, which is the large majority of what you write. This is the recommended home for a normal patch.
* **Late: finalize or remove.** Use the late pass for patches that wrap up: applying decisions based on what you collected, or removing assets, once everything else has had its say.

A few more notes:

* For a plain edit, set neither a pass nor a bucket. Default is correct, and leaving your patch there lets other mods order around it.
* `:First()` and `:Last()` are blunt, use them sparingly, and prefer [`:Before` / `:After`](/doc/dependencies-and-ordering-werp1yYh7P) against a specific patch when you only need to order relative to one other patch.
* When you need two of your own patches in a specific order, put them in the same bucket and use [`:Before` / `:After`](/doc/dependencies-and-ordering-werp1yYh7P).