Claude/daemon startup install yyuf77#51
Merged
Merged
Conversation
… is one switch
The field failure: with both palctl and the GUI running as the same user
(Path A), every GUI call answered "the daemon rejected the token." Root
cause: Windows builds a service's environment from the SYSTEM block —
%APPDATA% is an interactive-shell variable the SCM never sets, even for a
service logging on as that user. The --as-user service therefore fell into
config_dir()'s ~/.config fallback and read a DIFFERENT config folder (and
token) than the GUI. Latent since the wrapper swap: winsw_config_xml
deliberately skipped the APPDATA redirect when a service account was set
("user wins over the redirect") — and a test pinned that wrong behavior.
The redirect is now injected for user-account services too, it survives
the password scrub, and the GUI's 401 message explains the real cause and
fix instead of suggesting a re-registration that wouldn't have helped.
And per the design direction: the wizard's background section is ONE
switch, not a menu. The login-startup option is REMOVED from the wizard —
not disabled, not hidden. Every alternative to "service under your
account" either couldn't watch the server or couldn't run the Discord
bot; offering it was how users ended up in the broken split. The group is
checkable: background on (service as you, password field inline) or off.
A legacy "login" config value maps to service on the next run. PIN-only
accounts keep `palctl-daemon install-startup` as a console escape hatch.
Verified: 474 tests + ruff clean; offscreen Qt construction confirms the
login option is gone, on/off maps to service/none, the password field
follows the group state, and a legacy "login" config restores as service.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GSzfBCYS7ZrnGD7creTJaK
Signed-off-by: Claude <noreply@anthropic.com>
….config The APPDATA env injection fixed the service definition — but the deeper defect was the fallback itself: with %APPDATA% absent (every Windows service; the SCM never sets it), config_dir() fell back to ~/.config, a Linux convention that on Windows lands in a folder no GUI ever reads. Two config folders, two tokens, 401 on every GUI call — and the only cure was re-registering the service or hand-editing its XML. The fallback is now platform-correct: on Windows, <profile>\AppData\ Roaming — exactly where the GUI lives; ~/.config stays the non-Windows path. This makes the fix self-healing: even under an OLD service registration with no redirect, an updated daemon computes the same folder as the GUI. Updating palctl alone heals an affected install — no wizard re-run, no re-registration, no hand-edits. Belt (env injection) and suspenders (correct fallback), because a config split is a 401 the user cannot diagnose. Verified: 477 tests (3 new pinning all branches: APPDATA wins; Windows fallback = AppData\Roaming; Linux fallback = .config), plus an end-to-end simulation of the field scenario proving GUI and no-APPDATA service now resolve the identical directory where the old code diverged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSzfBCYS7ZrnGD7creTJaK Signed-off-by: Claude <noreply@anthropic.com>
Every failure that shipped this cycle lived in one seam: an interactive user's GUI talking to a service under that same account. The unit suite fakes the SCM (even on windows-latest) and install-lifecycle registers LocalSystem only — so the --as-user path and the GUI<->service token handshake were never executed by any machine before a user's. New as-user-lifecycle job, on a real Windows runner: - config_dir with no APPDATA must resolve to AppData\Roaming (the exact Linux-ism fallback that split the config and produced the same-user 401) - give the runner account a password, register the daemon as a user-account service the way the wizard does (non-interactive password) - THE HANDSHAKE: a client reading the token from the interactive %APPDATA% must get 200 from the service daemon's /state — the precise scenario that failed in the field as "the daemon rejected the token" - the account password must not persist in the WinSW XML (scrub proof on a real registration, not a faked one) - the health task is registered with the service and removed with it From here, "the as-user install works" is a claim CI makes by executing it, not a claim made in a PR description. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSzfBCYS7ZrnGD7creTJaK Signed-off-by: Claude <noreply@anthropic.com>
…gnored Bug #7, caught by the as-user-lifecycle CI job on its FIRST execution: the sc qc output in the green run read SERVICE_START_NAME : LocalSystem. palctl wrote <username> inside <serviceaccount>, but WinSW v2's schema is <domain> plus <user> — the unknown element is ignored without error and the registration silently falls back to LocalSystem while --as-user claims success. Broken since the NSSM->WinSW swap; invisible to every unit test (they assert the XML palctl writes, not what WinSW reads) and to the handshake probe (the APPDATA injection made even the LocalSystem daemon read the right config, so /state answered 200). winsw_config_xml now emits <domain> + <user> (".\name" and "DOMAIN\name" split; a bare name gets the local-machine domain "."), and the CI job now ASSERTS the logon account from sc qc instead of just printing it — the silent-fallback class is machine-checked from here on. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSzfBCYS7ZrnGD7creTJaK Signed-off-by: Claude <noreply@anthropic.com>
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.
What & why
How was it tested?
Checklist
pytestpassesruff check palctl testspassesgit commit -s) — opening this PR agrees to theCLA for its
contributions (see
CONTRIBUTING.md)
CHANGELOG.md