provision when the account list changes, not only when you connect

Receiving users:list updated an in-memory array and did nothing else, so a
person added to Officer next month reached Photos only if somebody remembered
to re-run provisioning by hand. The platform already broadcasts on every create
and delete, and re-sends on every sidecar registration — nothing was listening.

Now it acts on it. A restart is therefore also a reconciliation, which is the
cheap way to recover from any push that was missed while the sidecar was down.

An automatic run is NOT allowed to key an adopted account. Keying one means
resetting its password, because that is the only way Immich issues a key, and
for an account that pre-dated Officer that takes away a login somebody is using
— most likely in Immich's own app. Doing that unattended, to a person who did
not know it was at stake, is not the same act as the owner choosing it: so the
account is linked, left keyless, and named in `pending`. The deliberate
/provision route still does the whole job.

Tested against the case this is for: jrg.conceicao has an Immich library and no
Officer account today. When that account exists, the plan adopts the library
rather than building a second one beside it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 15:51:07 +00:00
co-authored by Claude Fable 5
parent a83da42a1f
commit 9b9b084734
4 changed files with 143 additions and 8 deletions
+5
View File
@@ -5,6 +5,7 @@ import { handleLockedRoute } from './locked';
import { handleOfficerRoute } from './routes';
import { getConfig } from './upstream';
import { setProvisionableUsers } from './user-list';
import { provisionForAccountChange } from './provision-run';
import { API_URL } from '@@/officer-url.mjs';
// The officer-photos sidecar. Owns the whole Immich contract for Officer: the instance URL and the API key.
@@ -155,6 +156,10 @@ function handleCommand(cmd: SidecarCommand, reply: ReplyFn) {
// not a question.
case 'users:list':
setProvisionableUsers(cmd.users);
// And act on it. Detached deliberately: this reaches out to Immich and can take seconds, while the
// command handler is on the socket the platform is waiting on. Nothing replies to `users:list`, so
// there is no answer to delay — but blocking here would stall every later message on this socket.
void provisionForAccountChange();
break;
default:
reply({