Skip to content

Commit 8934406

Browse files
docs(magos-modificus): strip phase/stage labels; add UI architecture (#45)
Per the operator's directive: project phase/stage/track labels, decision narratives, and future-work sections had leaked into committed docs and code comments. These have no meaning to a reader of the current state. ## What this PR does **Cleanup (mechanical, all preserved technical meaning):** - All Phase X / Stage Y / Track Z references stripped from docs/, AGENTS.md, README, magos-modificus/README.md, and ~36 code files (84 comment-level violations). Each rewritten to describe current state. - Status banners removed. Decision narratives removed. Future-work sections removed (MAGOS-MODIFICUS.md's 'Steam non-steam shortcuts' + 'Open / future'; nexus-rate-limiting.md's 'Open strategy questions'). The 'slim launcher' framing everywhere replaced with 'stub'. - AGENTS.md's 'no project phase/stage labels' convention rule extended to cover all docs + code comments (was scoped to docs/architecture + docs/reference only). **Content gaps filled (surfaced by _local/ spec survey):** - docs/reference/magos-modificus/config.md: added the missing NexusConfig schema + NexusAuthMethod enum + NexusOAuthTokens record, verified against source. - docs/architecture/ui-architecture.md (NEW): UI layer documented as components for the first time. Shell layout + the _syncing guard rationale, IProfileSession, ModListViewModel/ModItemViewModel, the per-mod update UI + BoolAllConverter, DmfPromptService (three cases + dialog-on-dialog avoidance), IDialogService, IPreferencesService, LocalizationService. - docs/reference/magos-modificus/ui.md (NEW): UI-layer public surface (IProfileSession, IDialogService, IPreferencesService, LocalizationService, DmfPromptService, UpdateCheckRunner, BoolAllConverter, DI registration, testing). - Doc-currency nits fixed: MAGOS-MODIFICUS.md no longer frames Stage 5/6 as future (both shipped); mod-acquisition.md step 3 updated to current content-based archive detection. ## Verification - Build: 0 warnings, 0 errors. - Tests: 292/292 UI tests pass (full suite verified by delegating agents). - Violation sweep: zero remaining Phase/Stage/Track/decision-narrative/future-work references across all docs + code (the only intentional exception is the example inside AGENTS.md's conventions rule itself, the 'don't write this' illustration). - No new em-dashes in new prose; drawn geometry for icons/markers in any rendered UI examples. ## What was NOT touched - The _local/ specs themselves (gitignored, local-only). - Pre-existing em-dashes in older docs (out of scope; only new content was held to the no-em-dash rule). A separate normalization pass could clean those if desired. - The Launcher stub itself (it IS a stub today; the slim launcher is unbuilt). Docs now describe it as a stub, not as 'Phase 5' or 'slim launcher'.
1 parent 994b4f8 commit 8934406

56 files changed

Lines changed: 1595 additions & 478 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 60 additions & 61 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ unmodified).
1010
## Components
1111

1212
- **Magos Modificus** (this repo): the mod manager app (UI, staging, load order,
13-
profiles, dependency resolution, mod-source integrations). Phases 0–3 are
14-
complete: the backend libraries (Profiles, Mods, Steam, Integrations,
15-
Enginseer-client, General) and the UI (the app shell + profile management,
16-
global Preferences, the mod-list UI, the Launch flow + Settings window) are
17-
in place. The app is user-usable. The Launcher is a stub (Phase 5). See
13+
profiles, dependency resolution, mod-source integrations). The backend
14+
libraries (Profiles, Mods, Steam, Integrations, Enginseer-client, General) and
15+
the UI (the app shell + profile management, global Preferences, the mod-list
16+
UI, the Launch flow + Settings window) are in place. The app is user-usable.
17+
The Launcher is a stub. See
1818
[`magos-modificus/README.md`](magos-modificus/README.md) for developer/build
1919
details.
2020
- **Enginseer runtime** (separate repo):

docs/architecture/MAGOS-MODIFICUS.md

Lines changed: 33 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,6 @@ Mods, Steam), and the "Launch Darktide" button that invokes the Enginseer
88
launcher. Enginseer does the injection + mod loading; Magos Modificus owns the
99
management experience around it.
1010

11-
> **Status: Phases 0–3 complete; Phase 4 in progress (Stages 1–4 done).** The
12-
> foundation (.NET 10 + Avalonia 12 layout, DI composition, structured logging,
13-
> global config schema/loader) plus the backend libraries are built: Profiles,
14-
> Steam, Integrations, Enginseer-client (Phase 1) + Mods (Phase 2). The Phase 3
15-
> UI is in place across all four tracks: Track A (app shell + profile
16-
> management), Track D (global Preferences + i18n), Track B (the mod-list UI +
17-
> local import), and Track C (Launch wiring + Settings window + discovery
18-
> escape-hatch). Phase 4 adds the Nexus integration: the nxm:// scheme handler
19-
> (Stage 1), Nexus auth + Integrations dialog (Stage 2), mod acquisition
20-
> (Stage 3), and the update-check service (Stage 4). The app is user-usable:
21-
> create profiles, import mods, manage the mod list, configure Settings, and
22-
> launch modded Darktide. The **Launcher** is a stub (Phase 5). It builds on the
23-
> [Enginseer runtime](https://github.com/ModifAmorphic/darktide-enginseer)
24-
> (separate repo).
25-
2611
## In scope for this document
2712

2813
- The component's role, technology choices, and project layout.
@@ -59,13 +44,12 @@ magos-modificus/
5944
profiles/ Profiles library — profile data, staging, mods.lst
6045
mods/ Mods library — unified mod repository (IModRepository) + version-policy + source models
6146
steam/ Steam library — Steam/Darktide/Proton discovery + IsGameRunning
62-
integrations/ Integrations library — GitHub Releases client (Nexus = Phase 4)
47+
integrations/ Integrations library — GitHub Releases client + Nexus v1 client/auth + mod acquisition + update check
6348
enginseer-client/ Enginseer-client library — the launch façade
64-
launcher/ (optional) slim profile launcher — launches a profile without
65-
the UI (entry point for Steam non-steam shortcuts); Phase 5
49+
launcher/ stub launcher — the Steam non-steam-shortcut target placeholder
6650
nxm/ Nxm library: nxm:// scheme-handler plumbing (URL parser, IPC
6751
server, single-instance guard, router + handler seams, OS
68-
registrar, relay helper); Phase 4 Stage 1
52+
registrar, relay helper)
6953
nxm-handler/ the OS-registered nxm:// scheme handler (native-AOT console
7054
exe; relays the raw URL to running Magos, or cold-starts it)
7155
tests/ xUnit test projects per library
@@ -86,7 +70,7 @@ UI models.
8670
| **Enginseer** | All interaction with the Enginseer runtime. v1 façade only: assemble launcher args, invoke, track process exit. (Live-control — status / hot-reload / live enable-disable — is a future Enginseer contract expansion; out of v1.) |
8771
| **Profiles + Settings** | Profile data, files, directories; global/system settings (logging, profile base folder, mod repository); resolves each profile mod's version policy to a repository version folder; materializes the profile mod root + writes `mods.lst` at launch. |
8872
| **Integrations** | External-service calls: Nexus Mods (primary user-mod source), GitHub Releases, local install. Nexus API key / OIDC, version checks, downloads / updates. |
89-
| **Steam** | Steam operations outside Enginseer: locate Steam (`libraryfolders.vdf`), Darktide install + compatdata, Proton version; add / remove non-steam shortcuts; detect whether the game is running. Owns the Linux discovery + escape hatch (see [Launch](#launch)). |
73+
| **Steam** | Steam operations outside Enginseer: locate Steam (`libraryfolders.vdf`), Darktide install + compatdata, Proton version; detect whether the game is running. Owns the Linux discovery + escape hatch (see [Launch](#launch)). |
9074
| **General** | Cross-cutting infra: DI composition, structured logging, configuration, shared primitives. |
9175

9276
## Composition & startup
@@ -120,11 +104,11 @@ through a registered library interface. The UI registers only its own surface
120104
the root and `IProfileService` always resolves its staging dependency).
121105
- `AddProfiles()`: profile service + the `SymlinkCreator` staging seam.
122106
- `AddIntegrations()`: the typed GitHub HTTP client + the typed Nexus v1
123-
HTTP client (Phase 4 Stage 2) + the Nexus auth service + the OAuth token
107+
HTTP client + the Nexus auth service + the OAuth token
124108
store + the loopback `IBrowser`.
125-
- `AddSteam()`: Steam discovery + the platform process-lookup seam.
126-
- `AddEnginseerClient()`: the launch façade + the process-launcher seam.
127-
- `AddLauncher()`: the slim profile launcher stub (Phase 5).
109+
- `AddSteam()`: Steam discovery + the platform process-lookup seam.
110+
- `AddEnginseerClient()`: the launch façade + the process-launcher seam.
111+
- `AddLauncher()`: the launcher stub.
128112
- `AddSingleton<MainWindow>()` + `AddSingleton<MainViewModel>()`: the UI
129113
surface.
130114
4. **Build**: `BuildServiceProvider()`.
@@ -254,7 +238,7 @@ an orphan (skip + warn); a "phantom" pin to a version that was never imported
254238
cannot be expressed (the policy editor offers only the container's actual
255239
versions, and `SetModPolicy` rejects an unknown id). GitHub release tags and
256240
Nexus file versions are arbitrary strings (not SemVer); there is no version
257-
ordering at this layer, and "newer" is decided later (Phase 4) by fetching the
241+
ordering at this layer, and "newer" is decided by fetching the
258242
latest release tag and checking string inequality.
259243

260244
Each container also carries a **source** (Untracked / Nexus / GitHub) so a
@@ -285,9 +269,9 @@ owner/repo. Version dedup: re-importing the same tag reuses its folder
285269
(refreshed); a new tag creates a new version + flips `isLatest`. The service
286270
returns `(containerId, versionString)`; the caller then adds the profile
287271
reference via `IProfileService.AddMod`. Remote acquisition (Nexus / GitHub API
288-
clients, auto-fetch) is Phase 4 Stage 3; the acquisition service downloads the
289-
archive to a temp path preserving the real Nexus `file_name` extension, then
290-
hands it to the import service.
272+
clients, auto-fetch) is handled by `IModAcquisitionService`; the acquisition
273+
service downloads the archive to a temp path preserving the real Nexus
274+
`file_name` extension, then hands it to the import service.
291275

292276
**Base-name collision hard-block:** two mods with the same base folder name
293277
can't coexist in one profile (the mod loader can't tell them apart). Before
@@ -372,23 +356,23 @@ is in [integrations reference](../reference/magos-modificus/integrations.md).
372356
## Mod acquisition
373357

374358
When a user clicks "Mod manager download" on Nexus, the
375-
[nxm handler](nxm-scheme-handler.md) relays the URL and the Stage 3
359+
[nxm handler](nxm-scheme-handler.md) relays the URL and the
376360
`NxmModDownloadHandler` orchestrates the download and import into the active
377361
profile. The reusable core is `IModAcquisitionService` (Integrations): it
378362
resolves the CDN download links, fetches mod metadata, downloads to a
379363
`.zip`-named temp file, and imports via `IModImportService`. The handler (in the
380364
UI assembly, not Integrations, because it coordinates UI-only services) checks
381365
auth and an active profile, calls the service, registers the mod with
382366
`LatestPolicy`, refreshes the mod list, and surfaces errors via
383-
`ShowAlertAsync`. Stage 5's per-mod update button calls the same service. Full
367+
`ShowAlertAsync`. The per-mod update button calls the same service. Full
384368
detail (the acquisition flow, the handler checks, the UI-assembly placement, and
385369
startup OS registration) is in [mod acquisition architecture](mod-acquisition.md);
386370
the public surface is in
387371
[integrations reference](../reference/magos-modificus/integrations.md).
388372

389373
## Update check
390374

391-
Stage 4's `IUpdateCheckService` (Integrations) is the Nexus-only update check.
375+
The `IUpdateCheckService` (Integrations) is the Nexus-only update check.
392376
On profile load it calls `ModUpdatesAsync("warhammer40kdarktide", Month)` once,
393377
intersects the response with the active profile's `LatestPolicy` +
394378
`NexusSource` mods, and flags any whose imported version's `ImportedAt`
@@ -398,19 +382,20 @@ regardless of profile size; `PinnedPolicy`, `UntrackedSource`, and
398382
`GitHubSource` mods are skipped. Rate-limit-aware: if the response reports an
399383
exhausted daily or hourly quota (and the limit was actually reported, guarding
400384
against the all-zero header-absent fallback), the result is flagged
401-
`RateLimited` and Stage 5 surfaces a "check incomplete" indicator rather than
402-
"all up to date." The full rate-limiting strategy (what Magos observes, how it
403-
reacts, what it does not do, and what consumes the budget) is documented in
404-
[Nexus API rate limiting](nexus-rate-limiting.md).
385+
`RateLimited` and the mod-list UI surfaces a "check incomplete" indicator
386+
rather than "all up to date." The full rate-limiting strategy (what Magos
387+
observes, how it reacts, what it does not do, and what consumes the budget) is
388+
documented in [Nexus API rate limiting](nexus-rate-limiting.md).
405389

406390
The result (`UpdateCheckResult` with per-mod `ModUpdateInfo`) is published via
407-
`LastResult` + a `CheckCompleted` event for Stage 5's badges to consume without
408-
re-awaiting. The check is fired fire-and-forget by `UpdateCheckRunner` (UI),
409-
which subscribes to `IProfileSession.PropertyChanged` filtered to
410-
`ActiveProfileId` (startup-with-restored-id + active-profile switch). No UI in
411-
Stage 4; Stage 5 adds the per-row "update available" badges + the per-mod
412-
update button (which calls Stage 3's `IModAcquisitionService`). The public
413-
surface is in [integrations reference](../reference/magos-modificus/integrations.md).
391+
`LastResult` + a `CheckCompleted` event for the mod-list badges to consume
392+
without re-awaiting. The check is fired fire-and-forget by `UpdateCheckRunner`
393+
(UI), which subscribes to `IProfileSession.PropertyChanged` filtered to
394+
`ActiveProfileId` (startup-with-restored-id + active-profile switch). The
395+
service itself has no UI; the mod-list UI consumes `LastResult` /
396+
`CheckCompleted` to render per-row "update available" badges + the per-mod
397+
Update button (which calls `IModAcquisitionService`). The public surface is in
398+
[integrations reference](../reference/magos-modificus/integrations.md).
414399

415400
## Mod list (main view)
416401

@@ -422,7 +407,7 @@ surface is in [integrations reference](../reference/magos-modificus/integrations
422407
- When DMF is installed, it appears as a protected first entry (locked first
423408
by dependency resolution; updateable).
424409
- **Hot-reload** — tied to the Enginseer live-control contract; out of v1.
425-
- **Dependency view** — out of v1 (uncertain value; revisit later).
410+
- **Dependency view** — out of v1.
426411
- **Conflict detection** — out of v1.
427412

428413
## Launch
@@ -483,11 +468,9 @@ run under Proton with `STEAM_COMPAT_DATA_PATH` + `STEAM_COMPAT_CLIENT_INSTALL_PA
483468
set by Magos.
484469

485470
**Known characteristic (not a defect):** when Magos launches directly, Steam
486-
isn't supervising the session (no overlay / playtime tracking). The **Steam
487-
non-steam shortcut** path is the answer for users who want full Steam
488-
integration — see below.
471+
isn't supervising the session (no overlay / playtime tracking).
489472

490-
### Launch wiring + Settings + escape-hatch (Phase 3 Track C)
473+
### Launch wiring + Settings + escape-hatch
491474

492475
The shell's `LaunchCommand` invokes `IEnginseerLaunchService.Launch(activeProfileId)`
493476
(gated by `CanLaunch`: a profile is selected and the game is not running) and
@@ -533,19 +516,6 @@ setter). The canonical names match `DiscoveryResult`'s field names, which are
533516
what `LaunchResult.MissingDiscoveryFields` carries, so the escape-hatch shows
534517
exactly the fields launch reported missing.
535518

536-
### Steam non-steam shortcuts
537-
538-
A shortcut added to Steam that launches Darktide with a specific profile, so
539-
Steam supervises the session (overlay, playtime). Created from Magos against
540-
the currently-selected profile.
541-
542-
- The shortcut's launch options bake in the resolved paths (compatdata, runtime
543-
dir, mod-path) at creation time, so firing the shortcut needs no rediscovery.
544-
- The optional **slim profile launcher** is the shortcut's target: a thin
545-
native binary that accepts a profile argument and does what the Launch button
546-
does. It reuses the Magos Steam library for discovery and the Enginseer
547-
library for invocation.
548-
549519
## Configuration
550520

551521
One global config file for system-level settings (structured — e.g. JSON or
@@ -570,32 +540,19 @@ Per-profile settings live with the profile, not in the global config.
570540
per-mod auto-update override, auto-sort + manual sequential reorder.
571541
- Mod storage (unified repository keyed by `(source, identity)`, version resolution by policy).
572542
- Mod sources: Nexus Mods (primary) + GitHub Releases + local; DMF via the
573-
open sourcing decision (Phase 4 — see Mod sources).
543+
new-profile prompt (Nexus mod 8).
574544
- Launch Darktide (Windows trivial; Linux native + Proton-at-launch +
575545
discovery + escape hatch).
576-
- Steam non-steam shortcuts.
577546
- Global config + per-profile settings.
578547
- DMF new-profile prompt.
579548

580-
**Out of v1 (deferred):**
549+
**Out of v1:**
581550

582-
- Enginseer live-control (status / hot-reload / live enable-disable) awaits
551+
- Enginseer live-control (status / hot-reload / live enable-disable): awaits
583552
an Enginseer IPC contract expansion.
584553
- Dependency-view mod list.
585554
- Conflict detection.
586555

587-
## Open / future
588-
589-
- **Enginseer live-control contract** — the IPC / status surface that would
590-
enable hot-reload, live enable/disable, and in-Magos status display. Tracked
591-
as a GitHub issue on Enginseer; when it lands, the Magos Enginseer library
592-
grows from a launch façade to a richer client, and the UI's mod list gains
593-
live controls.
594-
- **Slim profile launcher** — built alongside the Steam-shortcut feature;
595-
reuses the Steam + Enginseer libraries.
596-
- **Distribution / packaging** (.NET self-contained, AppImage, distro
597-
packages, etc.) — undecided; a release/delivery concern, not architectural.
598-
599556
## References
600557

601558
- [darktide-enginseer](https://github.com/ModifAmorphic/darktide-enginseer): the

docs/architecture/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ unmodified).
99

1010
## Component model
1111

12-
- **Magos Modificus (`magos-modificus/`)** (Phases 0–3 built): the user-facing
13-
app: staging-directory management, load order, profiles, dependency
14-
resolution, mod-source integrations, the Launch flow. The backend libraries
15-
and the UI are implemented (the app is user-usable); the Launcher is a stub
16-
(Phase 5). See [`MAGOS-MODIFICUS.md`](MAGOS-MODIFICUS.md) for the
17-
architecture.
12+
- **Magos Modificus (`magos-modificus/`)**: the user-facing app:
13+
staging-directory management, load order, profiles, dependency resolution,
14+
mod-source integrations, the Launch flow. The backend libraries and the UI
15+
are implemented (the app is user-usable); the Launcher is a stub. See
16+
[`MAGOS-MODIFICUS.md`](MAGOS-MODIFICUS.md) for the architecture.
1817
- **Enginseer runtime** (external): the injected modding runtime + its launcher.
1918
Lives in a separate repo,
2019
[darktide-enginseer](https://github.com/ModifAmorphic/darktide-enginseer).
@@ -26,6 +25,9 @@ unmodified).
2625
- [`MAGOS-MODIFICUS.md`](MAGOS-MODIFICUS.md): the Magos Modificus architecture
2726
(project layout, domain libraries, the Enginseer contract Magos consumes,
2827
profiles, the Windows/Linux launch paths, v1 scope).
28+
- [`ui-architecture.md`](ui-architecture.md): the UI layer (the shell, the
29+
profile session, the mod list, the update UI, the DMF install prompt,
30+
dialogs, preferences, and i18n).
2931
- [darktide-enginseer](https://github.com/ModifAmorphic/darktide-enginseer): the
3032
runtime architecture (the Rust↔C Hybrid, the seam, the launcher flow,
3133
discovery, the mod loader).

0 commit comments

Comments
 (0)