Skip to content

fix(install): stop -FromZip destroying host configuration - #46

Merged
vibesoftwarecoder merged 1 commit into
masterfrom
fix/preserve-host-config
Sep 10, 2026
Merged

fix(install): stop -FromZip destroying host configuration#46
vibesoftwarecoder merged 1 commit into
masterfrom
fix/preserve-host-config

Conversation

@vibesoftwarecoder

Copy link
Copy Markdown
Owner

Closes #45 — and the problem is larger than that issue described.

-FromZip wipes the whole install directory

Not just appsettings.json:

Get-ChildItem $InstallDir -Force | Remove-Item -Recurse -Force

So an upgrade destroyed appsettings.json and appsettings.local.json, dropped the shipped defaults in their place, backed nothing up, and said nothing.

That makes CLAUDE.md's advice — put host-local settings in appsettings.local.json, because a deploy cannot overwrite it — true of dotnet publish and false here. Correct-sounding guidance that does not hold on the path people actually upgrade with.

On the host where this was found the API survived by accident: ResolveApiKey falls back to a file in ProgramData that the wipe does not reach. Any setting without such a fallback was simply gone.

The fix

Both files are copied out before the wipe and copied back after. The host's appsettings.json wins over the shipped one — the shipped file is what a first install needs, not an upgrade. The copies live under ProgramData\MultiSeat\config-backups\<timestamp>\, outside the directory being wiped, and double as the backup.

Preserved byte for byte, not as text. The first version of this round-tripped through Get-Content/Set-Content and handed back a file two bytes longer, because Set-Content appends a newline and can change encoding. Harmless for JSON today, wrong in principle for a step whose entire purpose is to leave a file untouched, and a trap the moment anything preserved here is not JSON.

New settings are reported, not hidden. Keeping the host's file silently would conceal an option a release adds — the one real cost of preserving over replacing. The shipped and installed key sets are compared and anything new is named, with a note that it runs at its built-in default.

Verified on a real upgrade, not in a harness

Run against the published v0.6.3 asset on a live install, with two deliberate markers:

before  appsettings.json       E7AC4C57508AF9BF  1579 bytes
after   appsettings.json       E7AC4C57508AF9BF  1579 bytes
before  appsettings.local.json 60CC6361B5C0EB1F    81 bytes
after   appsettings.local.json 60CC6361B5C0EB1F    81 bytes
  • an edited MaxSeats survived the upgrade
  • a removed NvencPreset was correctly reported as newly added by the release
  • the service restarted clean and the API answered 200 with the preserved key

Parses under Windows PowerShell 5.1 and 7; all 29 scripts pass lint-scripts.ps1.

Not retroactive

Anyone already on 0.6.3 still has the destructive installer. This protects the upgrade after it ships, not the one they are on.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SQvL62WkT8xDWXqyjFCGDw

Closes #45, and the problem was larger than that issue described.

-FromZip does not merely overwrite appsettings.json. It WIPES the entire
install directory before copying:

    Get-ChildItem $InstallDir -Force | Remove-Item -Recurse -Force

so an upgrade destroyed appsettings.json AND appsettings.local.json and left
the shipped defaults in their place, with no backup and nothing said. That
makes CLAUDE.md's advice -- put host-local settings in appsettings.local.json,
because a deploy cannot overwrite it -- true of `dotnet publish` and FALSE
here, which is the worst kind of wrong: correct-sounding guidance that does
not hold on the path people actually upgrade with.

The API survived by accident on the host where this was found: ResolveApiKey
falls back to a file in ProgramData that the wipe does not reach. Any setting
without such a fallback was simply gone.

Both files are now copied out before the wipe and copied back after, and the
host's appsettings.json wins over the shipped one -- the shipped file is what
a FIRST install needs, not an upgrade. The copies live under
ProgramData\MultiSeat\config-backups\<timestamp>\, outside the directory being
wiped, and double as the backup.

Preserved BYTE FOR BYTE, not as text. The first version round-tripped through
Get-Content/Set-Content and handed back a file two bytes longer, because
Set-Content appends a newline and may change encoding. Harmless for JSON and
wrong in principle for a step whose whole purpose is to leave a file untouched.

Keeping the host's file silently would hide settings a release adds, which is
the one real cost of preserving over replacing. So the shipped and installed
key sets are compared and anything new is named, with a note that it runs at
its built-in default.

Verified on a real upgrade to v0.6.3 rather than in a harness:

  before  appsettings.json       E7AC4C57508AF9BF  1579 bytes
  before  appsettings.local.json 60CC6361B5C0EB1F    81 bytes
  after   appsettings.json       E7AC4C57508AF9BF  1579 bytes
  after   appsettings.local.json 60CC6361B5C0EB1F    81 bytes

with a deliberately edited MaxSeats surviving and a deliberately removed
NvencPreset reported as newly added. Parses under Windows PowerShell 5.1 and
7; all 29 scripts pass the linter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQvL62WkT8xDWXqyjFCGDw
@vibesoftwarecoder
vibesoftwarecoder merged commit 98b5cfa into master Sep 10, 2026
3 checks passed
@vibesoftwarecoder
vibesoftwarecoder deleted the fix/preserve-host-config branch September 10, 2026 14:02
vibesoftwarecoder added a commit that referenced this pull request Sep 10, 2026
version.txt 0.6.3 -> 0.6.4, plus the hand-written notes the release workflow
reads from docs/release-notes/<version>.md.

No code changes -- both shipping commits already merged: 98b5cfa (the installer
no longer destroys host configuration) and 459f88d (the documentation that
claimed it could not).

⚠️ The notes carry a correction. PR #46 and its commit message said the fix was
"not retroactive" and would protect only the upgrade AFTER the one carrying it.
That is wrong. The installer that runs during an upgrade is the one inside the
release just downloaded, not the one already on the machine -- the documented
command runs .\scripts\install-service.ps1 from the extracted folder. So
upgrading 0.6.3 -> 0.6.4 uses 0.6.4's installer and configuration IS preserved.
The only gap is running an older extracted installer against this zip.

Getting that backwards understates the release: it is not insurance for a
future upgrade, it protects the one the user is about to perform.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQvL62WkT8xDWXqyjFCGDw
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

-FromZip upgrade overwrites appsettings.json with no backup

1 participant