Repository navigation
Description
A hold nothing can recompute still renders as the live reason
UpdatePolicyContent.IsHeld(tag) answers "is there a hold record for this tag". Both production
readers use it to answer a different question — "is this why the install is not moving right
now" — and those stopped being the same question the moment a check could decline to evaluate.
Measured on memex, get @Admin/UpdatePolicy, 2026-09-09 10:42Z:
heldAt : 2026-09-07T22:27:17Z
heldTag : 3.0.0-ci.8057
lastCheckedAt : 2026-09-09T10:41:24Z <- 36 h later
lastCheckVerdict: "updates are disabled on this install (Admin/UpdatePolicy = None);
the registry was not listed."
HeldAt/HeldReason are written only by RecordHold, which runs only when a candidate is
actually evaluated. LastCheckedAt is written by RecordCheck on every check. Under
UpdatePolicyKind.None the check records "updates are disabled" and never evaluates — so the hold
is never revisited, never cleared, and the fresh LastCheckedAt beside it makes a two-day-old
record read as a current verdict.
#3795 (merged today) sharpens this: under policy None the BuildCompletion /
ModuleSetProposed triggers are now filtered out before they check, so the hold is frozen harder
than it was.
It has already caused one misdiagnosis
#3706 was filed on this exact frozen record. Its headline — "their retired floors hold every
self-update on memex forever" — read three floor lines as a live verdict. They were computed at
2026-09-07 22:27Z; #3648 (floors become advisory) merged 00:22Z and #3651 (only measured
unloadability holds) merged 01:10Z the next morning. The quoted evidence predates its own fix by
two hours, and nothing in the record says so. See
#3706 (comment).
Where it surfaces
| reader | line | what it says |
|---|---|---|
UpdatePolicySettingsTab.cs:211 |
if (content.IsHeld(tag)) |
renders ui.updateHeld — "this install is not moving because…" — with the stale reason quoted underneath |
PlatformUpdateStatus.cs:99 |
policy.IsHeld(latest) || blocked |
returns UpdateHeld on the About surface |
The tab does print ui.updateHeldAt, so the date is on screen — but it reads as when the hold
started, not as the last moment anything checked. A reader has no way to tell a live hold from a
frozen one.
The actual reason this install is not moving is already recorded, one field away:
updates are disabled on this install (Admin/UpdatePolicy = None).
What correct looks like
The record is fine — a durable note of the last evaluation is worth keeping. The presentation is
what conflates a record with a verdict.
- A predicate that distinguishes them, on the content itself (it already carries
Policy): a hold
is operative only while the checker that wrote it would still clear it. - The tab renders a non-operative hold as history — "when last checked on «date», «tag» was
held because …" — and states the current reason (updates are disabled) as the current reason.
New keys go in bothstrings.en.jsonandstrings.de.json. PlatformUpdateStatus.Derivestops returningUpdateHeldoff a non-operative note. A Red combo
verification is a recorded fact and keeps holding — the existing comment already draws exactly
that line ("the recorded verdict is the fact; IsHeld is the poller's note about it"); this
extends it to the case where the note can no longer be refreshed.
🚨 Not "clear the hold when updates are disabled" — that destroys the last real evaluation, which is
the only diagnostic an operator has when they turn updates back on.
Found while correcting #3706.
Activity
rbuergi commentedon Sep 9, 2026
Fixed by #3815, merged. Closing by hand — the merge queue does not fire
Closeslinks, which is how SocialMedia#155 and #3488 both sat open on landed fixes today.Verified on
origin/main, not on the PR:A frozen hold now renders as history — "This is a record, not a current verdict… nothing has re-checked
{tag}since «date»" — andPlatformUpdateStatus.Deriveno longer answersUpdateHeldoff a note nothing can refresh. A Red combo verification still holds: that is a recorded fact about the build, not a note about the poller.🚨 The record itself is deliberately not cleared when updates are switched off — it is the only diagnostic an operator has before switching them back on. Only the framing changed.
Follow-up owed in the other repository, declared on the PR:
npm run sync:i18n -- --ref <the merge sha>in MeshWeaver.Plugins, to carry the two keys into the React mirror. The mirror compares against a pinned core commit, so nothing reds until someone runs it.