fix(env): forward tenant params on env patched emit so cards live-update (#1750)#1751
Open
Antonio-RiveroMartnez wants to merge 1 commit into
Open
fix(env): forward tenant params on env patched emit so cards live-update (#1750)#1751Antonio-RiveroMartnez wants to merge 1 commit into
Antonio-RiveroMartnez wants to merge 1 commit into
Conversation
2e33cb9 to
8dcbc94
Compare
…pdate
The env card spinner never cleared on status transitions
(start->running, stop/nuke->stopped) until a manual page refresh.
updateEnvironment persists via this.patch(), which bypasses Feathers'
automatic event dispatch, so it emits the `patched` event manually. The
emit passed no publish context. Feathers' transport-commons passes the
third emit arg through UNCHANGED as the publish `hook` (and only
synthesizes a fake `{ path, service, app, result }` when it is absent),
so the global publish handler had no usable `context.path` /
`context.params`: under `mode: required_from_auth` it could not resolve
the tenant channel and suppressed the event to service-only sockets.
This hits background transitions hardest (health-monitor start->running,
executor stop/nuke->stopped) which fire outside any request scope and,
since #1737, outside any ambient tenant DB scope.
Add an emitServiceEvent() helper that builds a correctly-shaped
HookContext (path + params carrying the tenant) and use it for the env
`patched` emit, passing resolvedParams. Refresh worked because findAll
re-reads status directly, bypassing websockets.
Tests: helper unit tests; a configureRealtimePublish test proving a
manual emit routes to the tenant channel when the hook carries
params.tenant (no ambient scope); and an updated branches regression
test asserting the emitted hook shape.
Fixes #1750
8dcbc94 to
bc1e56f
Compare
mistercrunch
approved these changes
Jul 6, 2026
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.
Linked issue
Fixes #1750
Summary
emitServiceEvent(app, {...})helper (apps/agor-daemon/src/utils/emit-service-event.ts) that emits a Feathers service event with a correctly-shapedHookContext(path+params), so the global realtime publish handler can scope it.branchespatchedemit inupdateEnvironment(branches.ts), passingresolvedParamsso the tenant is resolvable.configureRealtimePublishtest proving a manual emit routes to the tenant channel when the hook carriesparams.tenant(no ambient scope), and an updated branches regression test asserting the emitted hook shape.Why / context
The env card spinner never cleared on status transitions (
start→running,stop/nuke→stopped) until a manual page refresh.updateEnvironmentpersists viathis.patch(), an override that callssuper.patch()and therefore bypasses Feathers' automatic event dispatch, so it emits thepatchedevent manually. The emit passed no publish context.The load-bearing detail (verified in installed Feathers source): transport-commons' publish listener passes the third
emitargument through unchanged as the publishhook(@feathersjs/transport-commonschannels/index.ts:67-71), and only synthesizes a fake{ path, service, app, result }when that arg is absent. Automatic events, by contrast, emit the fullHookContext(@feathersjs/feathersevents.ts:18). So a manual emit that passes raw params — or nothing — leavesconfigureRealtimePublishwithout a usablecontext.path/context.params. Undermulti_tenancy.mode: required_from_authit then can't resolve the tenant channel and suppresses the event to service-only sockets; browsers never receive it.This hits the terminal transitions users wait on, which for
kind/executor env variants are applied by background paths outside any request scope — and, since #1737, outside any ambient tenant DB scope:start→running— flipped by the health-monitor timer.stop/nuke→stopped— the executor path early-returns atstopping; the terminal write lands from an async executor-completion path.Because those paths have no ambient tenant scope, the tenant must come from the emitted hook's
params. The helper supplies exactly that.A hard refresh fixes it because the initial
findAllre-reads status directly, bypassing websockets.Implementation notes
emit(...)call sites in the daemon (e.g. theboardsemits inbranches.ts:743/965/975, and sites inregister-hooks.ts/register-routes.ts) share the same context-less shape and should be migrated toemitServiceEventin a follow-up audit — see below.hookmapping, and thatresolvedParamscarries.tenanton the background caller paths (health monitor / executor RPC).Validation / test plan
emit-service-event.test.ts— helper emits aHookContext-shaped third arg (path/params/method/id).realtime-publish.test.ts— abranches patchedevent whose hook carriesparams.tenantroutes to the tenant channel underrequired_from_authwithout ambient scope (previously would be suppressed).branches.test.ts— updated regression test asserts the emitted hook shape (path: 'branches',params.tenant). Verified it fails when the emit shape is reverted to raw params.vitest runon the three files — 69 passed.tsc --noEmit(agor-daemon) — clean. Pre-commit hooks — passed.required_from_authdeployment: start/stop/nuke akindenv and confirm the card clears the spinner without a refresh.Risks / rollout / rollback
mode: staticbehavior is unchanged (tenant resolves to the static id regardless).Out of scope / follow-ups
emitServiceEvent(branches.ts:743/965/975,register-hooks.ts,register-routes.ts,register-services.ts:299).stop/nukepath writesstopped(status not derived from tracked-pid liveness). That reconciliation path is separate from this event-delivery fix.