feat(updates): silence update mechanics — version/restart churn → logs, not the user#783
Open
JKHeadley wants to merge 1 commit into
Open
feat(updates): silence update mechanics — version/restart churn → logs, not the user#783JKHeadley wants to merge 1 commit into
JKHeadley wants to merge 1 commit into
Conversation
…s, not the user
The Agent Updates topic was flooding with update *mechanics* the user can't
use — raw version numbers and restart plumbing ("Just updated to v1.3.217.
Restarting…", "vX applied but I'm still running vY", cascade-batch "rolling into
the pending restart at HH:MM"). mature-update-announcements (#698) silenced the
*feature-announcement* path; this silences the *mechanics* path.
New pure module src/core/updateNotifyPolicy.ts classifies every update
notification into mechanics | interruption | actionable | failure-escalated;
AutoUpdater.notify() and the restart-handshake emit in server.ts gate on it at
their single notify funnel. Default kind is `mechanics` (silent) so any future
un-audited callsite stays quiet instead of spamming. The user now hears about an
update ONLY for: a new capability (the maturity layer), a restart actually
interrupting their active work right now (plain, version-free "back in a few
seconds"), or a genuinely stuck update. All restart/interruption copy rewritten
version-free.
Opt into a single quiet "just refreshed in the background" heartbeat with
`updates.backgroundRefreshHeartbeat: true` (default false = full silence); it can
never re-introduce version churn.
Tests: update-notify-policy (both sides of every branch) + update-notify-routing
(funnel wiring integrity). Updated notification-spam-prevention,
auto-updater-failures, graceful-updates-phase2, update-notification-topic-lock to
the new contract (mechanics silent; interruption/actionable version-free).
Agent awareness via CLAUDE.md template + PostUpdateMigrator (own content-sniff
guard). Spec + ELI16 + side-effects review + release fragment included.
Spec: docs/specs/quiet-update-mechanics.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Agent Updates topic was flooding with update mechanics the user can't use — raw version numbers and restart plumbing. Real messages from a live Updates topic:
Just updated to v1.3.181. Restarting to pick up the changes.Update to v1.3.217 was applied but I'm still running v1.3.218. The next restart should pick it up.Update v1.3.215 queued — rolling into the pending restart at 02:21…mature-update-announcements(#698) made the feature-announcement path silent-by-default. It never touched the mechanics path — these aren't announcements, they're hardcoded restart/version status. So the noise remained. (User feedback, 2026-06-04: "notifications that reference features the user has no clue about.")What this does
A single pure policy (
src/core/updateNotifyPolicy.ts) classifies every update notification intomechanics | interruption | actionable | failure-escalated.AutoUpdater.notify()and the restart-handshake emit inserver.tsgate on it at their single notify funnel. Default kind ismechanics(silent) so any future un-audited callsite stays quiet rather than spamming.The user now hears about an update ONLY when:
Everything else — version churn, restart-batch coordination, self-healing version skew, transient apply failures that retry — goes to the logs only. All restart/interruption copy was rewritten version-free.
Opt into a single quiet "just refreshed in the background" heartbeat with
updates.backgroundRefreshHeartbeat: true(default false = full silence); scoped so it can never re-introduce version churn.Callsite map
mechanicsmechanicsinterruptionactionablefailure-escalatedTests
update-notify-policy(both sides of every branch) +update-notify-routing(funnel wiring integrity: mechanics never callssendToTopic, the three reaching kinds do, option-B gating). 16/16.PostUpdateMigrator-quietUpdateMechanics(migration parity). 5/5.notification-spam-prevention,auto-updater-failures,graceful-updates-phase2,update-notification-topic-lock(mechanics silent; interruption/actionable assert no\d+\.\d+\.\d+leaks).AutoUpdater,AutoUpdater-cascade-dampener,restart-window, e2eself-heal-cascade-and-drift, integrationupdates-status-restart-immediately-route,stall-recovery-e2e.tscbuild clean.Migration parity & awareness
PostUpdateMigratorunder its own content-sniff guard.Process
Tier 1 via
/instar-dev(ELI16 + side-effects review + release fragment). The gate flagged Tier 1 as below the risk floor (PostUpdateMigrator touch + new config key) — recorded, not blocked; both are the lowest-risk instances (idempotent append-only awareness block; optional default-false flag). User pre-approved the approach (option A — full silence).Spec:
docs/specs/quiet-update-mechanics.md🤖 Generated with Claude Code
ELI16 — version/restart churn goes to the logs, not to you
Your Updates channel was filling with messages you can't use: "Just updated to v1.3.217. Restarting…", "still running v1.3.218, the next restart should pick it up", "rolling into the pending restart at 02:42" — meaningless version churn. This change sorts every update message into four buckets before it can reach you: mechanics (version/restart plumbing → logs only), interruption (a restart is about to hit your active work → a plain "back in a few seconds", no version numbers), actionable (auto-updates are off, so you'd have to say "update"), and stuck (an update genuinely failed after retries). Only the last three reach you. The default bucket is silent-mechanics, so any future message a developer forgets to classify stays quiet instead of accidentally spamming — forgetting fails toward silence, not noise. An opt-in flag exists for people who'd rather get one quiet "just refreshed in the background" note than total silence, and that flag can only ever surface that single message — it can't reopen the flood. Nothing important is lost: real interruptions and truly-stuck updates still reach you, just without the jargon.