Skip to content

[claude] Make in-app MSIX updates work on the App Installer track - #20

Open
myieye wants to merge 3 commits into
developfrom
claude/fwlite-in-app-update-appinstaller-track
Open

[claude] Make in-app MSIX updates work on the App Installer track#20
myieye wants to merge 3 commits into
developfrom
claude/fwlite-in-app-update-appinstaller-track

Conversation

@myieye

@myieye myieye commented Aug 18, 2026

Copy link
Copy Markdown
Owner

[Claude, autonomous]

Staging PR — never merge; promoted to sillsdev when polished (see FORK.md).

In-app updates have failed on every .appinstaller-tracked install since sillsdev#2496, silently. Three fixes:

  • The URL. AddPackageByAppInstallerFileAsync validates the URI's file name and rejects anything not ending in .appinstaller, throwing ArgumentException before any network call. download-latest?edition=windowsAppInstaller set that name only via Content-Disposition, so installing the downloaded file by hand worked and the app never could. New FieldWorksLite.appinstaller route serves the same content; the old route stays, since attached packages recorded it and the OS updater is fine with it.
  • 0x80073D02 was treated as a failed download. It means the update staged but couldn't register while the app is running — the "installs when you close the app" outcome we already advertise. Now reported as success.
  • The 2-minute timeout dropped the result, so a failure logged nothing and looked exactly like a working update. That's why this went unnoticed for two weeks.

Also stops passing ForceTargetAppShutdown, which terminates the app without letting FwData projects close. Staging plus registration at next activation reaches the same end state without the kill.

Fixes the check-on-open path too — same code path, no separate change needed.

Then the UI, since the previous copy was wrong once the backend worked. The update is staged, not installed, and leaving the app running is exactly the state where Windows eventually force-terminates it. RestartForUpdate stops the hosted services first so open FwData projects close through the normal path, then hands off to AppInstance.Restart; that API terminates the process rather than running MAUI's shutdown, hence the ordering. It only returns if the restart failed, in which case we close instead so the update still installs on the next launch.

Screenshots

Install-success state (Storybook Install Success story):

Update downloaded, with a Restart now button

Before, the same state read "Update installed successfully! Please restart the application." with no way to act on it.

Verified

dotnet build clean (0 warnings) on FwLiteMaui and LexBoxApi; svelte-check 0 errors; eslint clean; new GeneratedAppInstallerPointsAtADotAppInstallerUrl test passes; both changed stories render in a real browser (that's where the screenshot came from).

The .appinstaller requirement is confirmed empirically, not just from docs — probing the API on a real machine, a URL whose path ends in .appinstaller passes validation even when it 404s, while ?test=.appinstaller in the query string fails exactly like a URL without it.

Not verified

Whether AppInstance.Restart picks up the staged update on its relaunch. Registration happens at activation and a restart is an activation, so it should, but that needs a signed build plus a release newer than the installed one to exercise. Worst case the relaunch comes back on the old version and the update installs at some later launch, which is where we are today anyway.

Findings and constraints behind these choices are recorded in docs/research/msix-appinstaller-fwlite.md.

Three problems, all on installs deployed from a .appinstaller file:

AddPackageByAppInstallerFileAsync validates the URI's file name and rejects
anything not ending in .appinstaller, so every in-app update threw
ArgumentException before Windows saw a deployment request. The old
download-latest?edition=windowsAppInstaller URL set that name only via
Content-Disposition, which is why installing the downloaded file by hand worked
and the app never could. Serve the same content from a FieldWorksLite.appinstaller
route and point both the generated file and the client at it. The query-string
route stays: packages already attached recorded it as their update source, and
the OS background updater is happy with it.

0x80073D02 ("apps need to be closed") was reported as a failed download. It
means the update staged but couldn't register while the app is running, which is
exactly the "installs when you close the app" outcome we advertise, so treat it
as success.

The two-minute timeout dropped the deployment result, so a failure logged
nothing and looked identical to a working update. Log the outcome when it lands.

Also stop passing ForceTargetAppShutdown: it terminates the app without letting
FwData projects close, and staging plus registration at next activation reaches
the same end state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9f48a9a8-057d-4c27-942a-a0a9cdc1a660

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@deepsource-io

deepsource-io Bot commented Aug 18, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in ba45997...9635ae9 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Aug 18, 2026 12:45p.m. Review ↗
Docker Aug 18, 2026 12:45p.m. Review ↗
JavaScript Aug 18, 2026 12:45p.m. Review ↗
Shell Aug 18, 2026 12:45p.m. Review ↗
SQL Aug 18, 2026 12:45p.m. Review ↗
Secrets Aug 18, 2026 12:45p.m. Review ↗
PowerShell Aug 18, 2026 12:45p.m. Review ↗
CSS Aug 18, 2026 12:45p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

}

[Fact]
public async Task GeneratedAppInstallerPointsAtADotAppInstallerUrl()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method with return type `Task` does not follow the naming convention


The consensus in .NET is to have names of methods dealing with asynchronous operations suffixed with Async. One such example is Stream.ReadAsync from System.IO. Doing so improves readability and provides crucial information at a glance.

myieye and others added 2 commits August 18, 2026 18:15
An update installed from the in-app button is staged, not installed: Windows
swaps it in when the app next starts. The dialog claimed "Update installed
successfully! Please restart the application", and left the user to close the
app on their own, which is the state where Windows eventually force-terminates
the process to register the update.

Say what actually happened and offer a clean way out of it. CloseForUpdate quits
through the normal shutdown path, so FwData projects close properly instead of
being killed mid-flight.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An update installed from the in-app button is staged, not installed: Windows
swaps it in when the app next starts. The dialog claimed "Update installed
successfully! Please restart the application" and left the user to do it, which
is the state where Windows eventually force-terminates the process itself.

RestartForUpdate stops the hosted services first, so open FwData projects close
through the normal path, then hands off to AppInstance.Restart. That API
terminates the process outright rather than running MAUI's shutdown, hence the
ordering; it only returns if the restart failed, in which case we close instead
so the update still installs on the next launch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant