Two things get pinned, both get re-verified
Every proposal’sresolution.inputs records exactly what it was resolved
against — the observed hash of any live cloud state it read, and, for a
cross-stack reference, the neighbor
ledger’s pinned_head at resolve time. Before acceptance, re-verifying
means re-checking each of those against current reality:
- Live state moved — the resource this proposal read has since changed (someone else shipped a change, or drift occurred). The proposal is stale; the world it describes isn’t the current one.
- A neighbor ledger advanced — the pinned head no longer matches the
neighbor’s current
Head(). Even though nothing about this stack’s own resources changed, the value this proposal resolved from a neighbor might no longer be current.
Stale is a distinct outcome, not a failure
A stale proposal isn’t rejected and it isn’t an error — it’s its own proposal status, sitting alongsidedraft/accepted/applied. The fix
is always the same: re-resolve. A stale proposal’s content never gets
edited back into freshness in place, because that would mean its hash no
longer means what it originally meant.
Drift can go stale twice
Adrift_revert proposal carries the drifted state’s own observed hash
in its resolution inputs, not the restore target’s — deliberately, so
reverifying it answers “has reality moved again since I decided to
revert it,” not some other question. This is what makes staleness catch
a second drift between the moment ubx scan --propose revert ran and
the moment the revert gets accepted, using the exact same mechanism,
unmodified.
Full detail: docs/resolver.md
and docs/architecture.md’s
“Revert path” section in ubiquex.
