Skip to content

feat(magos-modificus): Phase 4 Stage 5 mod-list update badges + per-mod update - #43

Merged
ModifAmorphic merged 2 commits into
mainfrom
phase4/stage5-mod-list-updates
Jul 7, 2026
Merged

feat(magos-modificus): Phase 4 Stage 5 mod-list update badges + per-mod update#43
ModifAmorphic merged 2 commits into
mainfrom
phase4/stage5-mod-list-updates

Conversation

@ModifAmorphic

Copy link
Copy Markdown
Owner

What

Wires the update-check service into the mod-list UI: per-row update markers, a premium-only one-click Update button, a configurable periodic check + manual thorough check, and the comparison-basis fix for the update check.

UI (ModListView + ModItemViewModel + ModListViewModel)

  • Source badge is now a link: a HyperlinkButton opening the mod page (Nexus) or repo (GitHub). Untracked is a no-op.
  • Update-available marker: "Update available" text (linked to the files tab) alongside a drawn accent Ellipse. Conditional on the update check flagging that container.
  • Per-mod Update button (premium-only, hidden for non-premium): drawn download-arrow, calls AcquireLatestNexusAsync, shows an indeterminate spinner during, reloads on success (marker clears via a fresh check), alerts on failure. One update at a time.
  • Header: a refresh button for manual "check now" (with spinner), a rate-limit notice, and a "showing recent updates" notice after Month-only checks. The mod count was removed (stale-INPC bug).
  • Integrations dialog: a new "Update checks" section with a toggle (enable/disable periodic) + a NumericUpDown interval (1-1440 min, default 10).

Update check (UpdateCheckService + UpdateCheckRunner)

  • Periodic check (configurable interval, default 10 min, toggle): fires Month-only (1 API call). The manual "check now" fires CheckThoroughAsync which also does a per-mod ListModFilesAsync pass for mods outside the Month window, catching mods whose latest release is older than a month.
  • UpdateCheckResult gains a Thorough flag so the UI shows "recent-only" vs "complete" coverage.

Comparison-basis fix (ModVersion.RemoteUploadedAt)

The update check now compares the imported file Nexus publish date (RemoteUploadedAt, captured at acquisition) against the latest file publish date, not against ImportedAt (when Magos imported it). This fixes the bug where reinstalling an older file today masked available updates (the import time was newer than any past file upload).

RemoteUploadedAt flows: acquisition captures ModFile.UploadedTimestamp, passes it through Import to AddVersion to ModVersion.RemoteUploadedAt. The check falls back to ImportedAt for versions imported before this change (backward-compatible).

Backend (Integrations)

AcquireLatestNexusAsync: resolves the newest non-archived MAIN file and forwards to the existing AcquireFromNexusAsync (the premium/auth-only path). A shared LatestMain helper is used by both the acquisition and the thorough check.

Concurrency

The CheckCompleted handler marshals to the UI thread via an injectable Action seam (the established NxmModDownloadHandler pattern), preventing off-thread Mods iteration racing with UI-thread Reload.

Tests + verification

818 tests passing (+65 new). Operator UAT-verified: marker text, source-badge link, Integrations dialog interval controls, manual thorough check catches mods outside the Month window (Numeric UI scenario), marker clears after update. Build: 0 warnings.

Two convention refinements for agent output discipline:

1. Don't surface implementation-detail questions to the operator without
   grounding the actual problem in plain terms. Decide internal plumbing
   yourself; reserve surfaced questions for genuine forks (irreversible, UI
   design shape, external deps, real user-facing trade-offs). Includes the
   one-sentence-non-plumbing-WHY test.
2. AGENTS.md tweaks ride in the current PR; convention fine-tuning does not need
   its own docs PR.
…od update

Wires the update-check service into the mod-list UI: per-row update markers,
a premium-only one-click Update button, a configurable periodic check + a
manual thorough check, and the supporting fixes discovered during testing.

UI (ModListView + ModItemViewModel + ModListViewModel):
- Source badge is now a HyperlinkButton linking to the mod's Nexus page (or
  GitHub repo). The update-available marker shows 'Update available' text
  alongside a drawn accent Ellipse, linked to the mod's files tab.
- Per-mod Update button (premium-only, hidden for non-premium): a drawn
  download-arrow that calls AcquireLatestNexusAsync, shows an indeterminate
  spinner during, reloads on success (marker clears via a fresh check), alerts
  on failure. One update at a time.
- Header: a refresh button for manual 'check now' (with spinner), a
  rate-limit notice, and a 'showing recent updates' notice after Month-only
  checks. The mod count was removed (stale-INPC bug; operator's call).

Update check (UpdateCheckService + UpdateCheckRunner):
- Periodic check (configurable interval, default 10 min, toggle in the
  Integrations dialog) fires Month-only (1 API call). The manual 'check now'
  fires CheckThoroughAsync (per-mod ListModFilesAsync for mods outside the
  Month window, catching mods whose latest release is > 1 month old).
- UpdateCheckResult gains a Thorough flag so the UI can show 'recent-only'
  vs 'complete' coverage.

Comparison-basis fix (ModVersion.RemoteUploadedAt):
- The check now compares the imported file's Nexus publish date
  (RemoteUploadedAt, captured at acquisition) against the latest file's
  publish date, not against ImportAt (when Magos imported it). Fixes the
  bug where reinstalling an older file masked available updates.
- RemoteUploadedAt flows: acquisition captures ModFile.UploadedTimestamp ->
  Import -> AddVersion -> ModVersion.RemoteUploadedAt. The check falls back
  to ImportedAt for versions imported before this change.

Backend (Integrations):
- AcquireLatestNexusAsync: resolves the newest non-archived MAIN file +
  forwards to the existing AcquireFromNexusAsync (the premium/auth-only path).
  Shared LatestMain helper used by both the acquisition + the thorough check.

Concurrency: the CheckCompleted handler marshals to the UI thread via an
injectable Action<Action> seam (the established NxmModDownloadHandler pattern).

Tests: 818 passing (+65 new). Operator UAT-verified: marker text, source-badge
link, Integrations dialog interval controls, manual thorough check catches the
Numeric UI case, marker clears after update.
@ModifAmorphic
ModifAmorphic merged commit 423e146 into main Jul 7, 2026
2 checks passed
@ModifAmorphic
ModifAmorphic deleted the phase4/stage5-mod-list-updates branch July 7, 2026 03:44
ModifAmorphic added a commit that referenced this pull request Jul 8, 2026
🤖 I have created a release *beep* *boop*
---


## 0.1.0 (2026-07-08)


### Features

* **component-a:** Hybrid Rust+C discovery + shell + launcher
([#1](#1))
([491e5d1](491e5d1))
* **magos-modificus:** implement Phase 1 Enginseer-client launch façade
([#20](#20))
([7950ed1](7950ed1))
* **magos-modificus:** implement Phase 1 Integrations (GitHub Releases
client)
([#19](#19))
([781d65c](781d65c))
* **magos-modificus:** implement Phase 1 Profiles library
([#17](#17))
([f355ceb](f355ceb))
* **magos-modificus:** implement Phase 1 Steam discovery library
([#18](#18))
([8f6ec00](8f6ec00))
* **magos-modificus:** implement Phase 2 shared-first mod storage
([#22](#22))
([cf2af80](cf2af80))
* **magos-modificus:** Phase 3 Track B mod-list, import, source model
([#29](#29))
([5075cee](5075cee))
* **magos-modificus:** Phase 3 Track C launch + Settings + escape-hatch
+ base-folder mod loading
([#32](#32))
([c595700](c595700))
* **magos-modificus:** Phase 4 Stage 1 nxm scheme handler + IPC
([#34](#34))
([0017529](0017529))
* **magos-modificus:** Phase 4 Stage 2 Nexus auth + Integrations dialog
([#35](#35))
([0790a8e](0790a8e))
* **magos-modificus:** Phase 4 Stage 3 Nexus mod acquisition
([#36](#36))
([d01105f](d01105f))
* **magos-modificus:** Phase 4 Stage 4 Nexus update-check service
([#39](#39))
([1749e76](1749e76))
* **magos-modificus:** Phase 4 Stage 5 mod-list update badges + per-mod
update
([#43](#43))
([423e146](423e146))
* **magos-modificus:** Phase 4 Stage 6 DMF new-profile/auth prompt
([#44](#44))
([994b4f8](994b4f8))
* **magos-modificus:** scaffold .NET 10 + Avalonia 12 app + libraries
([#16](#16))
([d1fac91](d1fac91))
* **mod-loader:** own the load-order contract (mods.lst), drop DMF
prepend
([#14](#14))
([1ccb891](1ccb891))
* **release:** add Curator release pipeline
([#49](#49))
([01517e4](01517e4))
* **runtime:** engine-context proven — trampoline, Enginseer v1,
launcher fail-fast
([#4](#4))
([4565ba8](4565ba8))
* **runtime:** Enginseer v2 — mod loader + launcher config + logging
([#5](#5))
([1e65b3f](1e65b3f))
* **runtime:** package Enginseer with the runtime; relocate build files
to runtime/
([#6](#6))
([7221bdb](7221bdb))
* **ui:** Phase 3 Track A — app shell + profile management
([#27](#27))
([f7f8250](f7f8250))
* **ui:** Phase 3 Track D — Preferences + i18n + custom title bars +
icon
([#28](#28))
([c921650](c921650))


### Bug Fixes

* **enginseer:** DMF integration fixes — IO re-root, load timing,
destroy
([#7](#7))
([401759c](401759c))
* **magos-modificus:** multi-format archive import (zip + 7z + rar)
([#41](#41))
([ee4f5c6](ee4f5c6))
* **magos-modificus:** search all Steam libraries for the compatdata
prefix
([#21](#21))
([895fa2b](895fa2b))
* **steam:** detect running Darktide via /proc argv[0] under Proton
([#23](#23))
([c5f38c4](c5f38c4))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: ModifAmorphic <86930443+ModifAmorphic@users.noreply.github.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