Repository navigation
Hub disposal wedges before Quiescing: the action block never dequeues the buffered ShutdownRequest(Quiescing) #3593
Description
What is failing
MessageHub.Dispose() starts a hub's teardown by posting ShutdownRequest(Quiescing) to its action block (Hub Disposal Model). On every hub in this burst that message was still sitting in the buffer a full stall budget later — each report reads RunLevel=Started Disposal=Pending with the queue at buffer=1,deferred=0,exec=0,openGates=0: one buffered message, no turn executing, nothing deferred, no gates held. The disposal state machine never entered Quiescing; the teardown did not start. This is the report-only stall detector's "stalled below" verdict (event 7313, Teardown Layers) working as designed — the defect is what it found.
Probable cause — medium confidence, mechanism not proven
A hub with no executing turn should dequeue a buffered message immediately. The single buffered entry is most plausibly the ShutdownRequest that Dispose() itself just posted (intake is still fully open at RunLevel=Started, so a pre-disposal client delivery is the alternative). Either way the evidence points at the hub's own pump — an action block that accepts a message but never starts a turn — rather than at the child/join the verdict prose assumes ("the stall is in a hosted hub or a join it is waiting on"). The tell is last progress: sync/… → Started: these hubs finished initializing and were disposed in the same breath, so the suspect race is the init turn completing at/after Dispose() posted the shutdown request, leaving the block parked. Solid regardless: the whole population was disposed in the same instant — one cascade armed every watchdog at once — and every hub was still at Started one budget later.
Impact
One mass event, not many independent hangs: each hub was reported exactly once, within tens of milliseconds of the others, all on one memex-cloud portal pod, all sync/* SynchronizationStream hubs. Nothing is forced any more, so these hubs stay pending until they resolve or the caller's bound ends them (mesh teardown 30 s → host ShutdownTimeout 90 s → the K8s grace ceiling). If the pod was terminating, this stretches shutdown by up to that chain; if it was serving, each pending hub pins its stream, subscriptions and object graph until restart — the honestly-reported version of the 2026-07-01 zombie portal-hub storm. Whether the hubs recovered in the following budget is outside the captured window.
Where to look
MessageHub.OnDisposalStall(verdict 7313) andMessageHub.Dispose/MessageHub.HandleShutdownCoreinsrc/MeshWeaver.Messaging.Hub.- The pump in
MessageService: why does a buffered message never start a turn whileexec=0? Compare with the creation-window race in Hub Disposal Model — a hub still inStartinghas its init cancelled on entry, but these hubs show the init completed (→ Started); examine what the pump does when the init turn returns while a shutdown request is already buffered. - The captured lines truncate the recursive disposal snapshot after the hub's own entry — pull the full snapshot from Loki at the burst instant to see whether children/joins are actually named for these hubs; that decides between "own pump wedged" and "waiting below".
- Recipe for reproduction: Debugging Disposal, Storms and Leaks (
MESHWEAVER_MSG_TRACE, count distinct messages).
Duplicates: none found. The 2026-08-29 → 09-03 memex-cloud DISPOSAL DEADLOCK DETECTED storm was the old watchdog (those lines read RunLevel=ShutDown followed by [FORCE-TEARDOWN]); this fingerprint is the new report-only detector (RunLevel=Started, "Disposal is NOT forced") and files as a new shape. Incidents Admin/_LogIncident/1b713d0145006a84 and Admin/_LogIncident/be4ec56e4c2c4870 are different log sites.
Evidence
| Fingerprint | 969aad76bce7790c |
| Category | MeshWeaver.Messaging.MessageHub |
| Severity | Error |
| Namespace | memex-cloud |
| Pods | memex-portal-deployment-6457bb9544-qpdjd |
| Occurrences | 47 |
| First seen | 2026-09-07 11:36:41Z |
| Last seen | 2026-09-07 11:36:41Z |
Recent log lines
2026-09-07 11:36:41Z memex-portal-deployment-6457bb9544-qpdjd fail: MeshWeaver.Messaging.MessageHub[7313]
DISPOSAL DEADLOCK DETECTED: Hub sync/UiOjzwrALEuM4cCn-DoIIg made no teardown progress for 00:00:08 (last progress: sync/UiOjzwrALEuM4cCn-DoIIg → Started). RunLevel=Started, queue depth 1. No turn is executing on this hub, so the stall is in a hosted hub or a join it is waiting on — the diagnostics below name it. Disposal is NOT forced.
Hub sync/UiOjzwrALEuM4cCn-DoIIg RunLevel=Started Disposal=Pending Queue(buffer=1,deferred=0,exec=0,openGates=0,deliveryActionCompleted=False)
2026-09-07 11:36:41Z memex-portal-deployment-6457bb9544-qpdjd fail: MeshWeaver.Messaging.MessageHub[7313]
DISPOSAL DEADLOCK DETECTED: Hub sync/WRbyJEMkTUS43kc7P-zPDA made no teardown progress for 00:00:08 (last progress: sync/WRbyJEMkTUS43kc7P-zPDA → Started). RunLevel=Started, queue depth 1. No turn is executing on this hub, so the stall is in a hosted hub or a join it is waiting on — the diagnostics below name it. Disposal is NOT forced.
Hub sync/WRbyJEMkTUS43kc7P-zPDA RunLevel=Started Disposal=Pending Queue(buffer=1,deferred=0,exec=0,openGates=0,deliveryActionCompleted=False)
2026-09-07 11:36:41Z memex-portal-deployment-6457bb9544-qpdjd fail: MeshWeaver.Messaging.MessageHub[7313]
DISPOSAL DEADLOCK DETECTED: Hub sync/j9MeH31cf0-m69pg6UfR3g made no teardown progress for 00:00:08 (last progress: sync/j9MeH31cf0-m69pg6UfR3g → Started). RunLevel=Started, queue depth 1. No turn is executing on this hub, so the stall is in a hosted hub or a join it is waiting on — the diagnostics below name it. Disposal is NOT forced.
Hub sync/j9MeH31cf0-m69pg6UfR3g RunLevel=Started Disposal=Pending Queue(buffer=1,deferred=0,exec=0,openGates=0,deliveryActionCompleted=False)
2026-09-07 11:36:41Z memex-portal-deployment-6457bb9544-qpdjd fail: MeshWeaver.Messaging.MessageHub[7313]
DISPOSAL DEADLOCK DETECTED: Hub sync/dwTJP2rjeEyog9zQsApccg made no teardown progress for 00:00:08 (last progress: sync/dwTJP2rjeEyog9zQsApccg → Started). RunLevel=Started, queue depth 1. No turn is executing on this hub, so the stall is in a hosted hub or a join it is waiting on — the diagnostics below name it. Disposal is NOT forced.
Hub sync/dwTJP2rjeEyog9zQsApccg RunLevel=Started Disposal=Pending Queue(buffer=1,deferred=0,exec=0,openGates=0,deliveryActionCompleted=False)
2026-09-07 11:36:41Z memex-portal-deployment-6457bb9544-qpdjd fail: MeshWeaver.Messaging.MessageHub[7313]
DISPOSAL DEADLOCK DETECTED: Hub sync/MuBDgXnUM06xQ4Dw1v9erA made no teardown progress for 00:00:08 (last progress: sync/MuBDgXnUM06xQ4Dw1v9erA → Started). RunLevel=Started, queue depth 1. No turn is executing on this hub, so the stall is in a hosted hub or a join it is waiting on — the diagnostics below name it. Disposal is NOT forced.
Hub sync/MuBDgXnUM06xQ4Dw1v9erA RunLevel=Started Disposal=Pending Queue(buffer=1,deferred=0,exec=0,openGates=0,deliveryActionCompleted=False)
Opened automatically from Admin/_LogIncident/969aad76bce7790c. Recurrences are folded into this issue rather than opening new ones.
Activity
rbuergi commentedon Sep 7, 2026
#3615 merged. It does not fix the wedge — it makes the wedge nameable. Leaving this open.
Three of the four "facts" in this report were artefacts of the instrument
All from
MessageService.GetQueueSnapshot, which returned(mainQueue.Count, deferredQueue.Count, 0, gates.Count, !draining, …):exec=0measured nothing. It was a hard-coded literal — a leftover from the TPL-Dataflowera; there is no
executionBlockany more. "No turn is executing on this hub" is not what thatfield said. A verification step that cannot fail.
deliveryActionCompleted=Falsemeantdraining == true— a drain IS nominally in flight.The name said the opposite of the datum, and this is the most load-bearing field in the report.
last progress: … → Starteddid not mean the hub reachedStartedafterDispose().runLevelChangedis aBehaviorSubject, so the watchdog's own subscription insideDispose()immediately re-emits the CURRENT level as its "observing from here" mark. The simpler reading is
that the hub was already
StartedwhenDispose()subscribed — which removes theStarting→Startedrace from the candidate set entirely.And the verdict asserted a cause the snapshot cannot support: "the stall is in a hosted hub or a
join it is waiting on", on a hub at
RunLevel=Startedthat has not reachedDisposeHostedHubsandis therefore waiting on no child and no join. The taxonomy had a hole — queue non-empty, drain
latched, nothing dequeued — and that hole fell into the "stalled below" bucket, sending every reader
to children that do not exist. That is why 47 reports were unactionable.
Merged #3557 is inert here and was neither cause nor fix:
RefusesIntakereturns false whenrunLevel < Quiescing, and exemptsShutdownRequest/DisposeRequestunconditionally.What #3615 changed
Execution→DrainsInFlight, a real reading;DeliveryCompleted→Draining, naming itsown datum; a new
turnsDequeuedcounter incremented atmainQueue.Dequeue()(the existingturnsCompletedincrements inRunHandler's.Finally, so it counts HANDLER completions and isblind to a turn that never reached a handler); event 7316
DisposalPumpNeverDequeued; 7313 isnow guarded so it can only be printed when the hub actually is below; 7317 is an explicit
unknown rather than a wrong guess.
Falsified both ways — with only the verdict change reverted, the test fails on the old sentence and
passes on
THE PUMP IS NOT TURNING; the other four verdicts still pass (6/6 acrossDisposalStallWatchdogTest+DisposalDeadlockDiagnosticsTest+ the new test). The new test's leveris a
PausableTaskSchedulerviaWithTaskScheduler— it asserts on the emitted verdict, not thatdisposal completes, because asserting completion would claim a fix this PR does not make.
What remains — and the next discriminator
The wedge itself. Two mechanisms remain, and they could not be discriminated with the old
instrumentation, which is the finding:
ScheduleDrainOneusesTask.Factory.StartNew(…, turnScheduler)withoutTaskCreationOptions.PreferFairness, so from a ThreadPool thread it enqueues onto that thread'sLOCAL LIFO work-stealing queue;
HostedHubsCollection.DisposeHubsReactivedisposes every childsequentially on one thread, so N children's drains pile into that one thread's local queue,
reachable only by stealing. Reproduces every measured field on all N children at once.
carries a dotnet-stack note for that exact frame (
Monitor.Enter_Slowpath ← GetHub ← RouteStreamMessage ← DrainOne).One reading settles it at the next occurrence:
drainsInFlight=0and a dequeue delta of0⇒M1.
drainsInFlight ≥ 1and a delta> 0⇒ M2.🚨 Deliberately NOT done: no
PreferFairness, no retry, no watchdog re-kick, no widened bound.Each would make the symptom rarer while the mechanism is still unmeasured — and the fix for M1 and
the fix for M2 are in different places, so guessing has a 50% chance of leaving the real one live
and invisible.
One operational note, checked: nothing in
src/,.github/ordeploy/keys on the literal 7313sentence (only a doc comment), so the rename blinds no triage rule — the incident opener fingerprints
the line generically, and the pump shape will simply file as its own fingerprint under 7316.
Design recorded in
Doc/Architecture/DisposalStallVerdicts— field by field, what the snapshotactually measures, the taxonomy and its hole, and the M1/M2 table.
rbuergi commentedon Sep 9, 2026
#3798 merged. Leaving this open — it closes a third mechanism, it does not fix the wedge.
Same call #3615 made, and for the same reason: what merged is real but is provably not what the 47
sync/*reports were.What landed
The pump verdict still asserted the one load-bearing thing — "the drain flag is latched (a drain is scheduled on this hub's TaskScheduler)" — and nothing measured that parenthesis.
drainsInFlight == 0says no drain body is running; it does not say one is queued. Two states read identically and have opposite owners:drainsInFlightdrainsScheduled − drainsStartedTaskSchedulerMessageServiceM3 was reachable.
draining = trueis set inside the turn gate inKickDrain; the schedule happens outside it, andTerminal()re-schedules with the latch still held. A throw fromTask.Factory.StartNewat either site left the flag set with nothing outstanding — and sinceKickDrainreturns immediately whenever the flag is set, the pump froze for the life of the hub, silently, with this issue's exact fingerprint and a verdict blaming a scheduler that had never been asked.ScheduleDrainOnenow releases the latch and reports; it does not fall back to another scheduler, because the turn scheduler is the hub's serialisation guarantee.Why it is not your incident
Task.Factory.StartNewonTaskScheduler.Defaultdoes not throw.MessageHubConfiguration(IServiceProvider.CreateMessageHub) — nothing copies a parent'sTaskScheduler, which is exactly whatWithTaskScheduler's contract asks for ("use the grain's scheduler ONLY for the root grain hub").So
sync/*hubs run on the default pool scheduler, where M3 is unreachable and a dead activation scheduler cannot reach them either.What remains, and what now prints
M1-by-pool-starvation or M2, unchanged. The difference is that the next occurrence names itself: the verdict picks its
MECHANISM:clause fromdrainsInFlightanddrainsAwaitingSchedulerinstead of asserting one, andDoc/Architecture/DisposalStallVerdictscarries the three-way table plus the note that M3 does not apply to a hosted hub.Still no
PreferFairness, still no widened bound.rbuergi commentedon Sep 10, 2026
Reopened — the 2026-09-10 sweep was not a triage decision
This issue was closed
not_plannedat 2026-09-10T14:31:03Z by a bulk sweep that PATCHed every open issue in all 13Systemorphrepositories — 311 issues in twelve minutes, no comment on any of them — after a session was asked to "close all issues in all repos". Nothing on this thread was read, and no judgement was made about this issue.All 82 issues the sweep closed in the MeshWeaver fleet were reviewed afterwards. This one is unresolved: The author wrote "leaving this open" twice: #3615 and #3798 make the wedge nameable, they do not fix it.
Sixteen of the 82 were left closed — their fix had actually landed, or the author had withdrawn them; those should have read
completed, notnot planned.docs(#3432): the population is not #3593 — zero of 4,649 carry Dispos…
rbuergi commentedon Sep 11, 2026
Re-measured 2026-09-11 06:26–06:41Z — still OPEN, and for the reason this thread predicted: the wedge has not recurred, so the discriminating reading is still unavailable
The closing condition as this thread states it
Both merged comments say the same thing twice: #3615 and #3798 make the wedge nameable; they do not fix it. What closes this is the wedge — and the stated route is the reading at the next occurrence:
Instrument and numbers
1 — has it recurred? The incident this issue was opened from, read on the control instance memex.systemorph.com (
/api/version=3.0.0+45306a33e9437f1b662450dc23c4dfa6d897fe41, read 06:26Z):2 — is the instrument that would have caught a recurrence alive? Yes, and measured rather than assumed:
search 'namespace:Admin/_LogIncident content.namespace:memex-cloud sort:lastModified-desc'returns incidents from the same namespace this burst came from updated 2026-09-11T06:30:14Z — four minutes before the read. The scanner is ingesting memex-cloud today.3 — the rename does not hide a recurrence. #3615 moved the pump shape to its own event (
7316 DisposalPumpNeverDequeued), so a recurrence files under a NEW fingerprint.MessageHub.csis the logger, so it would file under theMessageHub:category. Denominator: 12 of 12MessageHub:-category incidents readable inAdmin/_LogIncident, non-truncated — none is a pump/teardown verdict, and the newest of the twelve isROUTER_TRAFFICat 2026-09-10T22:10Z. (Admin/_LogIncidentholds more than 200 incidents in total — the 200 listing came backtruncated: true— so the 12 is the category slice, not the store.)4 — is the naming code actually running on the portals? Verified by FILE/SYMBOL at the two commits the portals serve, not by ancestry:
MessageHub.cs:DisposalPumpNeverDequeuedMessageService.cs:DrainsAwaitingSchedulerorigin/main6231c4da…(memex.meshweaver.cloud)45306a33…(memex.systemorph.com)Verdict — OPEN
Nothing about the wedge is fixed, and four days without a recurrence is not evidence that it is: this fingerprint fired exactly once, as one mass event, on one pod. What has changed since the last comment is only that the naming code is now demonstrably running on both live portals, so the M1/M2/M3 reading will be printed by the next occurrence rather than having to be reconstructed.
What remains, named: the reading itself —
drainsInFlightanddrainsAwaitingSchedulerat a7316/7317occurrence. Plus the gap the 09-09 comment already recorded and which is unchanged: the verdict fires only from the disposal stall detector, so a hub merely stalled while alive never prints it — which is exactly the shape #2543 and #3674 keep hitting onportal/nodeops.Measured read-only through the portal API; no cluster access. Instruments:
get/searchon memex.systemorph.com,git cat-file/git showat the two running commits.rbuergi commentedon Sep 12, 2026
Re-checked 2026-09-12 against the 48-hour teardown wave — still OPEN, and this time the code is provably untouched
The 09-11 comment left this on "no recurrence, so the discriminating reading is still unavailable". The
question today is different: a large body of teardown work landed on 09-11 (#4042 / #4046 / #4048 /
#4053 / #4017 / #4029 / #4051, and MeshWeaver.Plugins#1680). Does any of it remove M1 or M2? It does
not, and the check is a file list rather than an argument.
1 — What landed, by file
744796d8dCompiler.Pipeline/CompilationCacheService.cs,Compiler.Pipeline/JsonMemberAccessorCacheEviction.cs,Mesh.Contract/Threading/CollectibleContextUnloads.cs,Threading/IoPoolServiceCollectionExtensions.cs(+4 lines), 3 test files, 2 docs5a10696fetest/MeshWeaver.Fixture/CollectibleUnloadDrain.cs,MonolithMeshTestBase.cs, 1 doccb724b571MonolithMeshTestBase.csonlyf1bd8c295MonolithMeshTestBase.cs, a new test, a csproj, 1 docb128b804d/ #4029dfc429b4aCompilationCacheService.cs,MeshNodeCompilationService.cs,KernelScriptReferences.cs, tests, docsa41c79742Hosting/NodeTypeBatchBake.cs, a test, docsNone of them touches
MessageService.cs,MessageHub.csorHostedHubsCollection.cs. Measureddirectly:
git log --since=2026-09-11 origin/main -- <those three files>returns nothing. The newestcommit on any of the three is
55ce6895b(2026-09-10 20:54, #3510's disposal-cause diag), so the codethis issue is about is byte-identical to what the 09-11 comment measured.
Two further readings, because "teardown work landed" invites both of the wrong ones:
src/the onlyconsumers of
CollectibleContextUnloadsare its registration (IoPoolServiceCollectionExtensions.cs:47)and
CompilationCacheService.RetireInto; the wait lives intest/(HubTestBase.cs:155/174,MonolithMeshTestBase.cs:298/1496,CollectibleUnloadDrain.cs). No hub teardown path subscribes to it.CollectibleUnloadDraincarries no timer and no cancellation: it endson the signal, on a fault, or on rounds that free nothing — which it reports as
RETAINEDrather thanwaiting or forcing. So there is no "we now abort in-flight work" story to reject here.
2 — The two live mechanisms, still exactly as #3615 left them
origin/maintodayMessageService.cs:1326—Task.Factory.StartNew(DrainOne, CancellationToken.None, TaskCreationOptions.DenyChildAttach, turnScheduler).PreferFairnesscount in the whole file: 0, at both commits the portals are running.HostedHubsCollection.cs:551DisposeHubsReactivestill callsh.Dispose()sequentially in the projection (:568), one thread for the whole wave.ScheduleDrainOne's catch releases the latch) and still fixed.3 — The instruments are running on both live portals (symbol check, not ancestry)
/api/versionMessageHub.cs : DisposalPumpNeverDequeuedMessageService.cs : DrainsAwaitingScheduler74d4c85274c99ec269(= today'smain)4 — Recurrence: zero — and which kind of zero
get @Admin/_LogIncident/969aad76bce7790c(control instance):occurrences 47,lastSeen 2026-09-07T11:36:41.157Z, nodelastModified 2026-09-07T11:41:56Z— unchanged since it was filed.search 'namespace:Admin/_LogIncident content.category:MeshWeaver.Messaging.MessageHub'→ 8 of 8,truncated: false; none of the eight is a 7316/7317 pump verdict (newest in the slice:ROUTER_TRAFFIC,2026-09-12T06:23Z).
Admin/_LogIncidentwere written at2026-09-12T06:29:08Z, three minutes before the read.
rbuergiand is RLS-filtered; "8 of 8"is the readable
MessageHub:slice, not a proof about every partition.simultaneous mass-disposal shape recurs daily on memex-cloud: at 2026-09-12T06:22:22.557–.783Z a dozen
root hubs (
Import,Chess×4,AppleWeather×2,Indexing,LossModelling,ReinsurancePractice, …)disposed inside ~300 ms on one pod — fingerprint
d2249f800ffc2577, event 7301. One cascade, every watchdogarmed at once, exactly the population shape of this issue's burst — and no 7316/7317 was printed by it. What
the incident store cannot say is whether any of those cascades reproduced M1's precondition (a saturated
pool thread whose local queue holds the children's drains); that is unobservable from outside, which is why
the closing condition is still a reading and not a count.
5 — Closing condition, unchanged
At the next
7316/7317:drainsInFlight = 0with aturnsDequeueddelta of0⇒ M1;drainsInFlight ≥ 1with a delta> 0⇒ M2.drainsAwaitingScheduler > 0separates "the schedulerholds it" from "nothing is outstanding". Nothing about the wedge is fixed; five days of silence on a
fingerprint that fired exactly once, as one mass event, on one pod is not evidence that it is.
Still deliberately NOT done: no
PreferFairness, no re-kick, no widened bound — the fix for M1 and the fixfor M2 live in different places.
Read-only:
git log/git show/git cat-fileonorigin/mainand on the two running commits;get/searchon memex.systemorph.com;
curl /api/versionon both portals. No cluster access, no mesh writes, no test runs.🤖 Generated with Claude Code
https://claude.ai/code/session_01KFBiMVHLTZM2axNgVvaZN2
feat: the pending-callback report prints the target hub's pump state
rbuergi commentedon Sep 13, 2026
The M1/M2 reading is now printed from a LIVE hub — #4154
This thread's closing condition is a reading at the next
7316/7317(drainsInFlight,turnsDequeueddelta,drainsAwaitingScheduler), and the 09-09 gap it recorded is that the verdict fires only from the DISPOSAL stall detector — a hub merely stalled while alive never prints it, which is the shape #2543/#3674 keep hitting.#4154 closes that gap from the other side. Under each pending callback whose target is a hub in this process, the pending-callback report (
[STALE-CALLBACK],[QUIESCE-TIMEOUT], the disposal snapshot) now prints the TARGET's pump:target pump now: <address> RunLevel=… turn=<message> running <ms> buffer=… deferred=… drainsInFlight=… awaitingScheduler=… draining=…. Read against this thread's table:draining=True drainsInFlight=0 awaitingScheduler=0with a non-empty buffer ⇒ M1 (the latch held, the drain never ran);drainsInFlight=1 turn=… running N ms⇒ M2 (a drain running, blocked before its handler — and the turn is named);awaitingScheduler>0⇒ the scheduler holds it. Measured need: on the Plugins gate's cut run of 2026-09-13 (#4141), 11SubscribeRequests sat atdepth=1on NodeType hubs for 31+ s with no line naming what those hubs were doing.Nothing about the wedge itself is changed by this; it stays open on the reading.
🤖 Generated with Claude Code
https://claude.ai/code/session_01BRLdhAiX5DjdZC2WUfPg9E
rbuergi commentedon Sep 13, 2026
2026-09-13 (later) — the M1/M2/M3 reading is armed and verified PRINTING; the wedge is byte-identical; no occurrence yet
Three things measured today, none of which changes the verdict: still OPEN.
1 — The reading prints, on a run rather than in a diff
#4154 (
e3d8ec06f, 08:37:54Z) puts this thread's discriminator on the pending-callback report of a hub that is merely stalled, not only one that is disposing — the gap the 09-09 comment recorded. Verified on core run34757233860, job103723972397Run tests (shard 2), 22 occurrences. Verbatim:Read against this thread's own table:
draining=True drainsInFlight=0 awaitingScheduler=0with a non-empty buffer ⇒ M1;drainsInFlight=1 turn=… running N ms⇒ M2, with the turn NAMED;awaitingScheduler>0⇒ the scheduler holds the drain. Every field is on the line.2 — The wedge itself is untouched, by file rather than by argument
On
origin/maintoday:MessageService.cs:1532—Task.Factory.StartNew(DrainOne, CancellationToken.None, TaskCreationOptions.DenyChildAttach, turnScheduler).PreferFairnesscount in the whole file: 0HostedHubsCollection.cs:568—DisposeHubsReactivestill callsh.Dispose()sequentially inside the projectionThe three pump files have moved only for #4183 (
75b13b165, a refused reply is reported to the requester) and #4178 (3c421609e, a hub disposing with its own deferred delivery logs Debug rather than Error) — neither touches whether a buffered message starts a turn.3 — Occurrence since the instrument shipped: none, and the denominator says which kind of none
target pump now:prints only inside a pending-callback report, so a green run printing none is expected. Between 08:37Z and ~15:45Z the bake/gate lanes that would produce one ran as follows: core CD's newest bake (34763464708/103746159798, 740 KB, a real mesh run — 4×ADVANCE_WITHOUT_HANDOFF) finished green with[STALE-CALLBACK]0; the Plugins gate (34764523308, 4 shards, real mesh runs) finished green; SocialMedia's one gate died at NodeType compile before any mesh started; and Reinsurance, Education, Manufacturing and Crm reached no gate at all (all post-merge attempts died atvalidate / Validate node reposor were cancelled). Each consumed core commit was checked by symbol, not ancestry —87805faaa,c9cd1f1b7,e50e4f588all carrytarget pump now×1 andreply#×1 — so the instrument was in what ran.I did not re-read
Admin/_LogIncidentthis session; the 09-12 reading of969aad76bce7790c(47 occurrences,lastSeen 2026-09-07) stands as last measured.Verdict
OPEN. Nothing about the wedge is fixed and nothing deliberately-not-done has been done: no
PreferFairness, no re-kick, no widened bound. What changed is only that the closing condition is now readable from a hub stalled while alive, and that the reading has been seen to print with all its fields — so the next7316/7317, or the next stalled-but-alive pump on a bake, names M1 / M2 / "the scheduler holds it" instead of having to be reconstructed.Read-only: GitHub REST (no GraphQL),
git show/git log/git merge-baseonorigin/mainand on the three consumed commits.🤖 Generated with Claude Code
rbuergi commentedon Sep 13, 2026
2026-09-13 (later still) — asked the two questions the thread had left open. Still OPEN, and the reading is still unobtainable — but one of the two is now settled by construction rather than by inspection.
The 15:59Z comment left this on "the reading is armed and verified printing; no occurrence yet". Two things were worth checking since, and neither had been:
RefusesIntakechange alter the mechanism? (fix(messaging): close the teardown intake gate at the first instant of disposal #3557's version was ruled inert on 09-07; the code has moved since.)1 —
RefusesIntakeis UNREACHABLE from this issue's state, and that is now a structural answer#4170/#4183 (
01a81f3c3d, merged as75b13b1651) really does changeRefusesIntake— 111 insertions inMessageService.cs. What it changes is theDisposeHostedHubstier:Every line of it sits inside the method's first guard:
This issue's whole population is at
RunLevel=Started.RefusesIntakereturnsfalseon that first line and never reaches the changed code. So the answer is not "I read the diff and it looked unrelated" — the diff is unreachable fromStarted, which is the state every one of the 47 reports carries. Same verdict as #3557, for a stronger reason.2 — The pump is byte-untouched since the instrument landed, by SYMBOL not by stat
MessageService.cs(+165/−10) andMessageHub.cs(+171/−2) have both moved sincee3d8ec06f(#4154), so a file-level "unchanged" would have been wrong. The relevant question is narrower — does a buffered message start a turn? — so the check is on the symbols that answer it:Zero hunks. And
HostedHubsCollection.cshas no diff at all in that range. Onorigin/main(783892a859) today:MessageService.cs:1532—Task.Factory.StartNew(DrainOne, CancellationToken.None, TaskCreationOptions.DenyChildAttach, turnScheduler).PreferFairnesscount in the whole file: 0HostedHubsCollection.cs:568—h.Dispose()sequentially insideDisposeHubsReactive's projectionThe commits that DID touch those files since #4154 —
e57ebd9395(#1140, theROUTER_TRAFFICreport names its call site),3c421609e6(#4178),01a81f3c3d/3bad2b7446(#4170/#4183),efebc3332a(#4067/#4068),636a8c556c(#4169) — are all intake, reporting or init-retirement. None is on the drain path.3 — Recurrence: still zero, with the instrument measured ALIVE at the moment of reading
get @Admin/_LogIncident/969aad76bce7790con the control instance (memex.systemorph.com):occurrences 47,lastSeen 2026-09-07T11:36:41.157Z, nodelastModified 2026-09-07T11:41:56Z,occurrencesAtLastComment 47— unchanged since it was filed, six days.7316).search 'namespace:Admin/_LogIncident content.category:MeshWeaver.Messaging.MessageHub'→ 8 of 8,truncated: false; none is a 7316/7317 pump verdict. Newest in the slice:ROUTER_TRAFFIC, 2026-09-12T21:15Z.Admin/_LogIncidentwere written at 2026-09-13T21:30:07Z, about five minutes before this read. So the six-day silence is an absence over a live instrument, not over a dead one.rbuergiand is RLS-filtered. "8 of 8" is the readableMessageHub:slice, not a proof about every partition.4 — Does #4154 make the reading OBTAINABLE? No — and it is worth being precise about why
#4154 puts the M1/M2/M3 discriminator on the pending-callback report, which closes the 09-09 gap (a hub stalled while alive could not print it). That is real and it is verified printing. But it does not reach this fingerprint:
target pump now:prints only inside a pending-callback report; a green run prints none, which is expected and is not evidence.sync/*SynchronizationStream hubs disposed en masse atRunLevel=Started. Whether any of them has a callback outstanding at that instant is not something the captured window says. The path that does cover this fingerprint is the disposal stall detector (7316/7317), and that was already armed by fix: the disposal stall verdict measures what it asserts (#3593) #3615/fix(#3593): a failed drain schedule must not latch the pump, and the verdict must measure its mechanism #3798 — nothing merged today widened it.So the closing condition is unchanged and unmet:
drainsInFlight = 0with aturnsDequeueddelta of0⇒ M1;drainsInFlight ≥ 1with a delta> 0⇒ M2;drainsAwaitingScheduler > 0⇒ the scheduler holds it.Verdict — OPEN, and deliberately nothing shipped
Still no
PreferFairness, no re-kick, no widened bound, no watchdog. M1 and M2 have fixes in different places; shipping one on a 50 % guess leaves the other live and, because the symptom would get rarer, invisible. A fingerprint that fired exactly once, as one mass event, on one pod, six days ago is not evidence that it is fixed — and it is not evidence that it is gone either. What changed today is only that the two ways it could have become stale (a pump edit, an intake-gate edit) have both been measured and neither happened.Read-only:
git diff/git show/git logonorigin/mainande3d8ec06f;get/searchon memex.systemorph.com. No GraphQL.🤖 Generated with Claude Code
rbuergi commentedon Sep 14, 2026
2026-09-14 — re-measured. Still OPEN, still not reproduced, and the mechanism is byte-unchanged.
The brief I was handed carried a warning worth recording: an earlier session reported "my hypothesis is falsified — the parked-turn case is caught earlier" just before being cut off. I did not re-walk what it eliminated; I started where this thread says to start — does the wedge still reproduce at all — and the answer is no, for a kind of "no" that has to be stated with its denominator.
1 — The incident has not moved in seven days
get @Admin/_LogIncident/969aad76bce7790con the control instance (memex.systemorph.com):occurrencesfirstSeen/lastSeenlastModifiedversionoccurrencesAtLastCommentUnchanged since it was filed.
2 — The positive control is stronger than "the scanner is alive" — it is a SIBLING incident written today
A zero over a dead instrument is not evidence. On the same store, read in the same minute,
Admin/_LogIncident/d2249f800ffc2577(the sibling teardown fingerprint, #3712) readslastModified2026-09-14T09:03:09Z,version249,lastSeen2026-09-14T08:57:09.895Z,occurrences364. SoAdmin/_LogIncidentis ingesting right now, and the seven-day silence on969aad76bce7790cis an absence over a live instrument.🚨 Denominator caveat, stated rather than glossed: this store is read as
rbuergiand is RLS-filtered. That is one incident record read directly by path, not a sweep, so the caveat is about whether a recurrence under a different fingerprint in a partition I cannot read exists — not about this record.3 — Both mechanisms are byte-present on today's
mainmaintodayMessageService.cs:1580—Task.Factory.StartNew(DrainOne, CancellationToken.None, TaskCreationOptions.DenyChildAttach, turnScheduler).PreferFairnesscount in the whole file: 0 (grep -c)HostedHubsCollection.cs:568—h.Dispose()still called sequentially insideDisposeHubsReactive's projection4 — What I merged today does NOT reach this, and saying so is the point
#4316 puts the disposal attribution (
requested by …; why: …) onto the[DISPOSE-DISCARD]reports and their NACKs, for #3712. That is the deferred-delivery arm of the teardown contract. It does not touch the pump, does not reach the7316/7317verdict, and does not make this thread's reading obtainable. It is listed here only so the next reader does not mistake a neighbouring teardown commit for progress on this one.5 — Closing condition, unchanged and unmet
At the next
7316/7317:drainsInFlight = 0with aturnsDequeueddelta of0⇒ M1;drainsInFlight ≥ 1with a delta> 0⇒ M2;drainsAwaitingScheduler > 0⇒ the scheduler holds it.Still deliberately NOT done, for the reason this thread has given three times: no
PreferFairness, no re-kick, no widened bound, no watchdog. M1 and M2 have fixes in different places, and shipping one on a coin toss leaves the other live and rarer, i.e. invisible.Read-only:
geton memex.systemorph.com;grep/grep -conorigin/mainin a worktree. No GraphQL, no cluster access, no mesh writes.🤖 Generated with Claude Code
systemorph-com commentedon Sep 19, 2026
Reopened — this fault is happening again.
Still occurring: 10 more since the last update (57 total).
memex-portal-deployment-69956b6dbc-gj8m2,memex-portal-deployment-6457bb9544-qpdjdRecent log lines
Re-addressed by the current identity function: this incident inherited
969aad76bce7790c(Systemorph/MeshWeaver.Plugins#1796). Those nodes are superseded and will not fold, file or comment again.systemorph-com commentedon Sep 19, 2026
Still occurring: 23 more since the last update (80 total).
memex-portal-deployment-69956b6dbc-gj8m2,memex-portal-deployment-6457bb9544-qpdjdRecent log lines
Re-addressed by the current identity function: this incident inherited
969aad76bce7790c(Systemorph/MeshWeaver.Plugins#1796). Those nodes are superseded and will not fold, file or comment again.rbuergi commentedon Sep 19, 2026
The discriminating reading finally arrived — and it is neither M1 nor M2. The titled defect is resolved; this issue is now carrying a different, third shape
This thread has said the same thing five times: #3615 and #3798 make the wedge nameable, they do not
fix it, and the closing condition is a reading at the next
7316/7317. The next occurrence hashappened. It is not a
7316, it is not the titled shape, and it settles both halves.1 — The titled defect: M1 is fixed and the original fingerprint is frozen and superseded
The title is "the action block never dequeues the buffered
ShutdownRequest(Quiescing)", measured asRunLevel=Started, buffer=1, exec=0. On the control instance:Twelve days, zero recurrence — and this time that is not dormancy measured across a quiet period.
memex-cloud rolled or restarted six times on 2026-09-19 (05:03Z, 05:50Z, 06:14Z, 06:35Z, 07:39Z,
08:32Z). Teardown is the path that fires this, it was exercised hard all morning, and it produced
occurrences of other shapes on the same instrument in the same minutes — so the silence on this
fingerprint is an absence over a live instrument under the regime that provokes it. That is the control
the #1540 family's reopens showed was missing, and here it is satisfied.
And M1 — the mechanism this thread named — is fixed and on the running image.
MessageService.ScheduleDrainOnenow asks forTaskCreationOptions.PreferFairness(
MessageService.cs:1658), so the drain goes to the ThreadPool's GLOBAL queue instead of the postingthread's LIFO local queue.
git merge-base --is-ancestor 4c8b5815f2 c25f86ae85b7⇒ true (fix2026-09-15 19:02Z; the running image built 2026-09-19 07:32Z). The code comment states it plainly:
"That was #3593's mechanism."
🚨 The successor's own triage draft agrees, independently of me:
2 — What the 80 occurrences actually are
The growth 47 → 80 is the re-addressing bot folding successor fingerprints onto this issue, not the
titled shape recurring.
23170794ce38a460holds 33 occurrences of a new shape,lastSeen 2026-09-19T08:58:09Z, and it is a three-level chain pinned by one leaf:Read against this thread's table: the pump turned (both ancestors dequeued turns; the leaf reached
Quiescing), so it is not M1;drainsInFlight=0, so it is not M2; M3 stays fixed. Thetitled premise — "the action block never dequeues the buffered ShutdownRequest" — is falsified for
this population: it was dequeued.
3 — Three defects found, all in the instrument or the state machine, all fixed in #4924
I traced it from the code rather than from more log-reading. Findings, each verified at the site:
(a) The 7314 verdict asserts a cause that is unreachable at this phase — the same defect #3615 fixed
for 7313 and left in its sibling.
DisposeImpl→disposables.DisposeandmessageService.Disposeare reached only from
case MessageHubRunLevel.ShutDown:inHandleShutdownCore. The leaf is atQuiescing, so "a registered cleanup is BLOCKING inside DisposeImpl or messageService.Dispose … findthe registrant" is false by construction — no registrant has run. The branch keyed on the message
type alone, with no phase check. This cost a full investigation through every disposal registrant of a
sync/*hub (a dozen, inSynchronizationStream/JsonSynchronizationStream; none reachable atQuiescing). 7314 is now phase-guarded, and 7318 states what is true below ShutDown: the findingis the phase transition, with the
QuiesceTimeout × MaxQuiesceRearms ≈ 42 sceiling to read 253 sagainst, and the
[QUIESCE-*]lines that separate "the wait never completed" from "it did and thehand-over was lost".
🚨 It had no test at all —
grep -rn DisposalShutDownPhaseBlocked src/ test/returns only the sitethat emits it. Checklist item 7 from
AFailureReportAnswersItsOwnInstruction, collecting anothervictim: a path no test can reach is a path whose wording nobody checks.
(b) The Quiescing→DisposeHostedHubs hand-over was the one phase advance with no guard. Its sibling
PostShutDownPhasehas always caught a failedPostand calledSignalDisposalFaultedso waiters onDisposalCompletedare released. The Quiescing advance was a barePostin afinally— and thecatcha few lines above it exists precisely because a throw there "would wedge the dispose statemachine at Quiescing forever (worse than the original hang)". The one statement that comment is
about sat outside it. A lost
Postleaves exactly the observed shape:Quiescing,buffer=0,drainsInFlight=0,draining=False,Disposal=Pending, no further line of its own, every ancestorblocked behind it. Now force-faults — which is the opposite of swallowing: the fault is reported and
the waiters above are freed.
(c)
Executing(ShutdownRequest, 253055ms)described a turn no thread was in. The snapshot isself-contradictory under this file's own invariants, and that is the finding: a handler holding the
block synchronously requires
drainsInFlight >= 1(a turn runs only insideDrainOne); a turn parkedasynchronously leaves
DrainLoopwithout clearing the latch, so it requiresdraining=True. Neitherheld. Cause:
RunHandlersetcurrentlyExecutingMessageTypenear its top and cleared it in a.Finallyattached ~260 lines later, so a throw between the two left the field set with nothing toclear it (
Observable.Defermakes such a throw a downstreamOnErrorwith theFinallyneverattached). The elapsed then reads as time since a stamp nobody cleared — and a verdict keys on it.
ExecuteOnTargetnow stamps throughObservable.Using, which disposes its resource both ontermination and when the observable factory throws, so no exit path can stamp without arming the clear.
turnsCompleteddeliberately stays in theFinally— it counts HANDLER completions and must stayblind to a turn that never reached one.
This is the second time a field on this snapshot has described something it could not measure. The
first was
exec=0, a hard-coded literal, found by this same thread on 2026-09-07.4 — Honest limits
PreferFairnessadded (it was already there), nore-kick, no retry, no watchdog, no widened bound.
closes the hole by construction; the orphan is measured (the contradictory snapshot) even though
its throw site is not located.
RunLevel < ShutDownwithCurrentMessage == ShutdownRequestneeds either the orphan (now closed)or a blocking Quiescing turn, and neither has an injectable seam — which is precisely why 7314 was
untested and its prose wrong. What I do have: all three are provable by reading the sites above, (a)
and (b) change only which line is logged / whether a fault is reported, and the full messaging
suite passes 483 tests, 0 failed with all three in place, which is the evidence (c)'s hot-path
relocation needs — that it is behaviour-preserving.
turn out to be the same event seen from two ends — same delivery id
AfJyOHs0WUu57CggZ5yWkg, samehub
RiskTransfer, same pod, six seconds apart on 2026-09-08 — which is recorded on both of those.Verdict
Open, but for a different reason than yesterday: the titled defect is resolved (M1 fixed, on the
image, fingerprint frozen and superseded across six rolls), and this issue is now the ticket for the
successor's third shape. The three fixes above remove the instrument defects that made that shape
unreadable and close the one state-machine hole that produces exactly its signature. What closes this
is the next occurrence of
23170794ce38a460on an image carrying #4924: a 7318 naming thetransition, or a 7314 that is now only printed where a registrant genuinely can block.
Taxonomy, the read-order caveat and the 2026-09-19 sighting are written up in
Doc/Architecture/DisposalStallVerdicts.Read-only for the measurements:
getonAdmin/_LogIncident/{969aad76bce7790c, 23170794ce38a460}on memex.systemorph.com;git merge-base --is-ancestor/grep/dotnet build/dotnet testin a worktree. No GraphQL, no cluster access, no mesh writes.🤖 Generated with Claude Code
rbuergi commentedon Sep 19, 2026
Correction to the comment above: the PR is #4931, not #4924
My previous comment cites
#4924twice — in "all fixed in #4924" and "the next occurrence … on animage carrying #4924". That number was written before the pull request existed and is wrong.
fix/3593-verdict-phase-and-quiesce-advance.and a re-addressed incident freezes the old one"). Apologies for the stray cross-reference it will
have picked up; nothing in it relates to this issue.
So the closing condition reads: the next occurrence of incident
23170794ce38a460on an image carrying#4931 — a 7318 naming the phase transition, or a 7314 printed only where a registrant genuinely can
block.
review(#3593): 7318's guidance is per PHASE, not one Quiescing senten…
rbuergi commentedon Sep 21, 2026
Cluster triage: this symptom has five distinct roots
Reviewed together with #1540 #1547 #1548 #3243 #3593 #2833 #2480 #5064 #4859 #5136 #4847 #4883 #4888 #4961 — every one of them reports
ObjectDisposedExceptionwithAutofac.Core.Lifetime.LifetimeScope.ThrowDisposedException()on top, or a teardown that did not finish. They are not one bug. The grouping, the discriminators and the evidence are committed asDoc/Architecture/DisposedScopeAndDyingHubs(added in #5159).Fixed — and the fix is confirmed deployed by #4847's own reading.
Grouped in
Doc/Architecture/DisposedScopeAndDyingHubsunder the hub-teardown-wedge family (with #4847, #4883, #4888).#4847's verdict line states the #3593 fix is live ("ScheduleDrainOne asks for PreferFairness since
#3593"), which is the drain now being queued globally rather than onto the posting thread's local
queue — visible to every worker and to the pool's own starvation detection.
That makes the residual readable instead of ambiguous, and it is tracked on #4847: with the drain queued
globally,
drainsAwaitingScheduler=1+TurnsDequeueddelta 0 can only mean the CLR thread pool had nothread to give, so M1-by-pool-starvation is now a diagnosis rather than a guess. The leading
candidate for what saturated the pool —
DrainLoop's trampoline owning a worker for an unbounded run ofsynchronous turns — is a different change from this one and belongs there.
Leaving the closure of this one to whoever confirms no
RunLevel=Started, buffer=1, exec=0mass eventrecurs on a rolled portal; the mechanism it reported is addressed.
rbuergi commentedon Sep 22, 2026
The five roots — what is merged, what is in flight, what is not
Measured against
origin/mainatbc7fe79551(2026-09-22) and the fourteen issue timelines. There is no open pull request in this repository at all, so nothing is in flight to adopt; every "unfixed" row below is genuinely unowned.Doc/Architecture/DisposedScopeAndDyingHubs)5946ea4d4b(2026-08-14):MeshTeardownHostedServicedrains inStoppedAsync(commita2906a04fd"fix(#1548): drain the mesh in StoppedAsync, after every other hosted service"). Pinned byMeshTeardownRunsAfterEveryOtherHostedServiceTest.7ce4c432cc(2026-09-22,HostedHubsCollection.Track); (2) the routing service's local route is value-matched — PR #5159,77d8dcf5fa(2026-09-21,OrleansRoutingService.RegisterStream, Monolith twin). (3) the pod-hub cluster claim (PodHubGrain.Detachstamps a terminal tombstone regardless of who holds the address) has not landed, andGetHubWithOutcomestill answersAvailablefor a hub atRunLevel >= ShutDown. The page's "Addunreferenced" lead is settled by #5191:Addis called fromMessageHubConfiguration.Build.77d8dcf5fa(2026-09-21) — three delete-pipeline sites hoisted, lease-release arm reordered. #5099: PR #5163,7a39fb2412(2026-09-22) — the per-hub-SCOPED case, where the hoist is cosmetic;DependencyNetworknow enumerates fromMeshExtensions.ReadIssuingHub. Both are compiled core code; neither has been verified on a rolled image yet, and neither thread reports a post-fix recurrence. The swept inventory (32 T1 sites, 4 fixed) is sized work with no issue attached.7e78e35c9d(2026-09-19):IoPoolSiloTeardown's expiry names the pool and the leaf.RoutingQuiescenceSiloParticipantprintsStuck leg(s)at expiry (PR #4923 lineage). No occurrence since either landed has named a leaf or a leg — neither thread carries one, and theLogsaction refuses from this session — so there is nothing to implement: the page and both triage notes refuse a guessed subject, and I agree.IMessageHubGrain.DeliverMessagereaches its sender or is silently lost. It reaches the sender:RoutingGrain.DeliverToGrainRoute'sCatcharm NACKs after the transient retries, andSiloUnavailableExceptionisIsShutdownShaped→ErrorType.ShuttingDown(transient, recovery machinery stays armed) since PR #4923,fa34bd2a7b(2026-09-19). Not silently lost; no fix to write.Adjacent, and not one of the five roots:
b1bcbd6c86(2026-09-19)e58a86e14e(2026-09-19)Dispose()names its cause), caller not identified11481fed16(2026-09-20)PinnedBlockMemoryPool, not an Autofac scope; correlation step namedSo the one root with no fix and a fix that can be written today is R2. Next: one PR for it — the pod-hub claim made value-conditional (prerequisite 3), and the lookup no longer handing out a hub that has reached
ShutDown— with a deterministic repro red on the current code. R4 stays on the instrumentation until an occurrence names its subject; R5 needs no code.rbuergi commentedon Sep 22, 2026
R2 is now in flight: #5199 — the lookup retires a hub at
ShutDownand mints a successor (kept in the owner's join), and the pod-hub claim's release is value-matched grain-side, which was the third prerequisite the page named. Controls on both sides are in the PR body. Per the table above, R4 stays on its instrumentation until an occurrence names its leaf/leg, and R5 needs no code; this issue itself stays open for its own post-roll verification (#4931).rbuergi commentedon Sep 23, 2026
Closing: both shapes this issue carried are fixed and deployed, and neither has recurred since the fix
This is the post-roll check the 09-22 comment left open ("this issue itself stays open for its own post-roll verification (#4931)").
1. The titled shape is the buffered
ShutdownRequest(Quiescing)never dequeued, read asRunLevel=Started, buffer=1.PreferFairnessinScheduleDrainOne(4c8b5815f2).969aad76bce7790chas been frozen at 47 occurrences since 2026-09-07. That held across the six memex-cloud rolls of 09-19, as measured on the control instance in the 09-19 comment.2. The successor shape the bot folded here on 09-19 is
sync/*parked atQuiescingbehindExecuting(ShutdownRequest, 253 s).b1bcbd6c86, merged 2026-09-19 20:03Z): the phase-guarded 7314/7318 verdicts, the Quiescing→DisposeHostedHubsPostforce-faulting instead of parking, and theExecuteOnTargetstamp cleared on every exit path.git merge-base --is-ancestor b1bcbd6c86 39f49494ebis true, and39f49494ebis what memex.meshweaver.cloud (namespacememex-cloud, where this issue's population lives) serves today (/api/version, read 2026-09-23 04:3xZ).3. No recurrence, and the silence was checked against a live reporter:
DISPOSAL/MessageHub[731x]/RunLevel=: 0 hits.DISPOSAL DEADLOCK: only the 09-19 bodies of Hosted sync hub's disposal drain starves on an exhausted thread pool (M1-by-pool-starvation, post-#3593) #4847 and sync/ hub teardown wedges: a registered disposal cleanup blocks the ShutDown phase on the action block #4883. Neither has had a bot recurrence since.The residuals are not this issue and stay tracked where they are:
What I did NOT establish:
Admin/_LogIncident/23170794ce38a460directly. ThesystemorphMCP was down this session, andmemexansweredNot found, which does not separate "absent" from "not readable".If the successor shape recurs, the bot reopens this issue.