case 4690 - NET10-PORT: tick or reword older open items with current evidence

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 17:07:53 -07:00
parent 181b1e446e
commit 4351ee9706

View File

@@ -54,11 +54,11 @@ them. Items touching those three areas carry more weight here than they did in S
## 0. Before changing anything
- [x] Record any port work already done in earlier sessions (branch, commits) here first, and reconcile it with this list. Done: branch `net10-port` and the 8.3.0 version bump (`c2f2f922`); no code changes yet
- [ ] `raven` and `raven-client` clean on `main` and pushed
- [x] Annotated tag `net8-baseline` on the pre-port commit in `raven` and `raven-client`. Present locally in both; confirm on the remote with `git ls-remote --tags origin`
- [x] `raven` and `raven-client` clean on `main` and pushed. Checked 2026-10-23: in both repos `main` = `origin/main` = `net8-baseline` (no port work on `main`)
- [x] Annotated tag `net8-baseline` on the pre-port commit in `raven` and `raven-client`. On the remote in both (`git ls-remote --tags origin`, 2026-10-23)
- [x] Branch `net10-port` created and pushed with upstream (`origin/net10-port` exists in `raven`)
- [x] **First commit: version bump** in every place listed in `devdocs/build/BUILD.md` → "Version numbers" (`c2f2f922`, 8.3.0)
- [x] Dev machine has the .NET 10 SDK and keeps the .NET 8 runtime for baseline comparisons. SDK 10.0.103 (no 8 SDK; the 10 SDK builds `net8.0`); runtimes 8.0.24 and 10.0.3
- [x] Dev machine has the .NET 10 SDK and keeps the .NET 8 runtime for baseline comparisons. SDK 10.0.103 (no 8 SDK; the 10 SDK builds `net8.0`); runtimes 8.0.24 and 10.0.3. Since 2026-10-23 also SDK 10.0.402 with runtime 10.0.13 (section 5)
### Gates (prove on the unmodified code)
@@ -70,24 +70,24 @@ them. Items touching those three areas carry more weight here than they did in S
- **Other checks in `Parse`** (`License.cs:926-1062`): `LicenseFormat == "8"`; `DBID` equals the server's schema id; perpetual key only on a perpetual build and subscription key only on a subscription build; `MExBB`, which rejects a perpetual non-trial key whose maintenance expiry is before **the build date, read from the PE linker timestamp** (`util/FileUtil.cs:861-882`). That timestamp is only a real date because `<Deterministic>False</Deterministic>` (`AyaNova.csproj:12`). Turning determinism on, or getting the CA2022 change at `FileUtil.cs:875` wrong, would reject perpetual licences with E1020. The gate must cover `MExBB`, not only the signature
- **When it runs:** at boot, `BootSafetyCheck` before any schema update (`Startup.cs:603`), then `InitializeAsync` (`Startup.cs:633`); after every fetch, `FetchKeyAsync` → `InstallAsync` → `InitializeAsync`, either manually (`LicenseController.cs:125`) or from `CoreJobLicense` (`generator/CoreJobLicense.cs:80`). Fetch interval (`CoreJobLicense.cs:21-34`): perpetual build 30 min while unlicensed, trial or expired, otherwise 24 h; subscription build 30 min; DEBUG 1 or 5 min. The installed key is not re-verified on a schedule; expiry is checked in CoreJobSweeper, according to the comment at `CoreJobLicense.cs:10`
- **Test access:** `Parse` is `private static` and depends on the static `ServerDbId` and on the running assembly's timestamp. The test needs `InternalsVisibleTo` or reflection
- [ ] **Report baseline.** Render the advanced reports on the unmodified build and keep the PDFs for comparison. Sockeye shares only one report with AyaNova, so Sockeye's testing says little about AyaNova's reports. **John's decision (2026-10-22): no recorded baseline; John verifies the reports visually himself** (see section 4)
- [ ] **E2E baseline.** Cypress run (`raven-test\e2e`) against a devtest server on the unmodified build. **Skipped for now (2026-10-22): not practical at this point.** Run later as a smoke test on the .NET 10 build (section 4)
- [x] **Report baseline.** Waived (John). Render the advanced reports on the unmodified build and keep the PDFs for comparison. Sockeye shares only one report with AyaNova, so Sockeye's testing says little about AyaNova's reports. **John's decision (2026-10-22): no recorded baseline; John verifies the reports visually himself** (see section 4)
- [x] **E2E baseline.** Waived (John, 2026-10-22: not practical at this point); replaced by the Cypress run on the .NET 10 build, still open in section 4. Was: Cypress run (`raven-test\e2e`) against a devtest server on the unmodified build
## 1. Framework and packages
- [x] `net8.0` → `net10.0`, with every framework-matched `Microsoft.*` package to 10.x in the same step (`AyaNova.csproj:3`). Done for the server: JwtBearer, Mvc.NewtonsoftJson, EntityFrameworkCore, ApiDescription.Server, HealthChecks.EntityFrameworkCore → 10.0.13; Npgsql.EntityFrameworkCore.PostgreSQL → 10.0.3 (required by EF 10); `.vscode/launch.json` program paths → `net10.0`. Builds with no new code changes. `raven-launcher.csproj:5` still to do
- [x] `net8.0` → `net10.0`, with every framework-matched `Microsoft.*` package to 10.x in the same step (`AyaNova.csproj:3`). Done for the server: JwtBearer, Mvc.NewtonsoftJson, EntityFrameworkCore, ApiDescription.Server, HealthChecks.EntityFrameworkCore → 10.0.13; Npgsql.EntityFrameworkCore.PostgreSQL → 10.0.3 (required by EF 10); `.vscode/launch.json` program paths → `net10.0`. Builds with no new code changes. Launcher: next item
- [x] `raven-launcher`: `net8.0` → `net10.0` (no package references). `raven-launcher` `d2079c9`
- [x] **Hosting model.** n/a: `Program.cs:330-351` already uses `Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(...)` with `UseStartup<Startup>`. Only a commented-out `BuildWebHost` line remains (`:308`)
- [x] **Asp.Versioning.** Done: 8.1.0 → 10.2.1 (as Sockeye), explicit `.AddMvc()` added between `AddApiVersioning` and `AddApiExplorer`. New analyzer suggestions AV0015 (use `UrlSegmentApiVersionReader` only) and AV0016 (`AssumeDefaultVersionWhenUnspecified`) deliberately not acted on: both would change which requests deployed clients can make. Was already: `Asp.Versioning.Mvc` and `.ApiExplorer` 8.1.0 (`AyaNova.csproj:36-37`), wired at `Startup.cs:200-217` as `AddApiVersioning(...).AddApiExplorer(...)`. Remaining: bump to 10.x and confirm `AddApiExplorer` still registers MVC versioning without an explicit `.AddMvc()`. Leave AV0014 warnings: **do not add `[ApiController]`**
- [ ] **Npgsql / EF Core 10.**
- [x] **Asp.Versioning.** Done: 8.1.0 → 10.2.1 (as Sockeye), explicit `.AddMvc()` added between `AddApiVersioning` and `AddApiExplorer`. New analyzer suggestions AV0015 (use `UrlSegmentApiVersionReader` only) and AV0016 (`AssumeDefaultVersionWhenUnspecified`) deliberately not acted on: both would change which requests deployed clients can make. Was already: `Asp.Versioning.Mvc` and `.ApiExplorer` 8.1.0 (`AyaNova.csproj:36-37`), wired at `Startup.cs:200-217` as `AddApiVersioning(...).AddApiExplorer(...)`. Leave AV0014 warnings: **do not add `[ApiController]`**
- [x] **Npgsql / EF Core 10.** EF Core 10.0.13, Npgsql EF 10.0.3 (item above)
- [x] `Npgsql.EnableLegacyTimestampBehavior`: n/a, commented out (`Program.cs:26`)
- [ ] `ConfigureWarnings(w => w.Throw())` **is present** (`Startup.cs:179`). Every new EF warning becomes an exception naming its ID: fix the query, or move that ID to `.Log(...)`
- [ ] Exercise LINQ-based queries screen by screen. Data-list filters build raw SQL and are unaffected
- [x] `ConfigureWarnings(w => w.Throw())` **is present** (`Startup.cs:179`). Every new EF warning becomes an exception naming its ID: fix the query, or move that ID to `.Log(...)`. **No EF warning has been raised as an error** on .NET 10 (checked 2026-10-23): the integration suite at every step, both droplets (24.04 and 26.04, including 22/22 reports), the `devtestn10` upgrade and the Windows Sandbox installs. Searched the local dev-server and Sandbox logs and the droplet logs: no "An error was generated for warning"; the only EF entries are expected `DbUpdateException`s from integration tests that deliberately break a constraint, and connection retries while PostgreSQL was starting
- [x] Exercise LINQ-based queries screen by screen. Through the API: the integration suite (CRUD on every tested object) at every step. Through the UI: moved to the Cypress E2E item in section 4. Data-list filters build raw SQL and are unaffected
- [x] **BouncyCastle.** Already `BouncyCastle.Cryptography` 2.3.1 (`AyaNova.csproj:28`) with MailKit/MimeKit 4.5.0; no `Portable.BouncyCastle` in the graph. Version bump only: now 2.7.0, moved together with MailKit 4.18.1, as in Sockeye. The Sockeye note about `PemReader` and PKCS#1 key pairs does not apply: AyaNova reads a public key (see the licence gate)
- [x] **Swashbuckle 10 / OpenAPI.NET 2.** Done: all six `Swashbuckle.AspNetCore*` 6.5.0 → 10.3.1 (Sockeye: 10.2.3), explicit `Microsoft.OpenApi` reference removed (now 2.7.5 transitively), and the three code changes below. Applies. `Microsoft.OpenApi.Models` merged into `Microsoft.OpenApi`: `using` at `Startup.cs:15` and `ConfigureSwaggerOptions.cs:6`. Bearer requirement (`Startup.cs:235-244`) becomes `c.AddSecurityRequirement(document => new OpenApiSecurityRequirement { [new OpenApiSecuritySchemeReference("Bearer", document)] = [] })`. Remove the explicit `Microsoft.OpenApi` 1.6.14 reference (`AyaNova.csproj:47`)
- [x] **NLog 6.** Done: NLog and NLog.Web.AspNetCore 6.2.2; `ArchiveNumbering` removed; **`ArchiveFileName` kept and `ArchiveSuffixFormat = "-{0}"` added** (`Program.cs`); log viewer sorts archives by file date, newest first. Tested in a scratch program and on the server, against a folder seeded with NLog 5 archives `-0` to `-8`: without `ArchiveFileName`, NLog 6 writes straight into numbered files (no `log-ayanova.txt`) and appends to the old `-8`; with it but no suffix format, archives become `log-ayanova_NN.txt` (NLog 6 ignores `{#}`) and the old `-0` to `-8` are never deleted. Sockeye 8.1.0 ships that second form. With both settings: `log-ayanova.txt` stays current, archives are `log-ayanova-N.txt` as the manual (`docs/.../ops-log.md`) says, numbering continues after the old files, and the old files are cleaned up. `NLogBuilder.ConfigureNLog` is already replaced (`Program.cs:206`, `LogManager.Setup().LoadConfiguration`). `ArchiveNumbering = Rolling` (`Program.cs:136`) is gone in 6. Archive numbers keep incrementing and the un-numbered file is always current. **The log viewer sorts by file name as a string** (`LogFilesController.cs:120`, `OrderByDescending(z => z)`), so `-10` sorts after `-2`. Fix the sort in the same commit
- [x] **Newtonsoft.Json.** `Mvc.NewtonsoftJson` 10.x sets a 13.0.3 floor (NU1605). Already resolved 13.0.3 transitively; now a direct reference at 13.0.4 (current; Sockeye pins 13.0.3)
- [ ] **JwtBearer 10.x.** The IdentityModel part is n/a: it resolves 7.1.2, not the vulnerable 6.10.0
- [x] **JwtBearer 10.x.** Done: 10.0.13 with the framework step (first item); login tokens still `HS256` and accepted on every authenticated call (log, 2026-10-22). The IdentityModel part is n/a: it resolves 7.1.2, not the vulnerable 6.10.0
- [x] **SMTP.** n/a: `util/Mailer.cs` already uses MailKit's `SmtpClient` (`:1`, `:84`); no `System.Net.Mail`
- [x] **PuppeteerSharp 17 → 25.x.** Reporting is AyaNova's main Puppeteer surface (`biz/ReportBiz.cs`). Done: 25.15.0 (Sockeye: 25.12.0); compiles with no API changes; launch arguments fixed (below). Downloads Chrome for Testing 155 (was 124). The download location and failure handling are separate section 3 items
- [x] `BrowserFetcher.DefaultChromiumRevision`: n/a, already `DownloadAsync()` with no argument (`ReportBiz.cs:800`, case 4586)
@@ -96,7 +96,7 @@ them. Items touching those three areas carry more weight here than they did in S
- The default download is Chrome for Testing, into `Chrome/` and `ChromeHeadlessShell/` beside the app. AyaNova 8.2.0 already moved from Chromium to Chrome to follow Puppeteer's default, so the browser choice is settled
- [x] Launch arguments must be separate array elements. Fixed: defaults are `new[] { "--no-sandbox" }` (`--headless` dropped, `LaunchOptions.Headless` already adds it, as in Sockeye); the customer setting is split on whitespace. A customer value containing a quoted argument with spaces would now be split; none is known. **Browser default locale:** the old `--headless` argument ran Chrome's old headless mode, which takes its default language from the OS (en-CA → Chrome's en-GB, day-first); current Chrome headless always defaults to en-US. Report scripts that format without a locale (stock sample report 80 calls `toLocaleDateString()` bare) switched from 22/10/2026 to 10/22/2026. Fixed by adding `--lang=<server CultureInfo.CurrentCulture>` unless the customer setting already has a `--lang`; skipped when the server culture is invariant. Stock helpers in `ay-report.js` pass the client's language explicitly and were never affected. **Both paths were wrong:** the defaults are one element `"--headless --no-sandbox "` (`ReportBiz.cs:812`, `:829`), and `AYANOVA_REPORT_RENDER_BROWSER_PARAMS` is passed whole as one element (`:819-822`)
- AppArmor restricts unprivileged user namespaces on Ubuntu 24.04+, which affects the Chrome sandbox
- [x] Remaining packages to current releases. **Done:** Bogus 35.5.1 → 35.6.5 (evaluation seeder), jose-jwt 5.0.0 → 5.3.0 (login tokens), QRCoder 1.5.1 → 1.8.1 (2FA setup QR). `dotnet list package --outdated`: nothing; `--vulnerable --include-transitive`: none. MailKit 4.5.0 carried a moderate advisory (NU1902); on `net10.0` the audit also reported high-severity NU1903 for `MimeKit` 4.5.0 and transitive `System.Security.Cryptography.Pkcs` 8.0.0. **Mail done:** MailKit/MimeKit 4.18.1, BouncyCastle 2.7.0, and `System.Security.Cryptography.Pkcs` 10.0.13 pinned directly (MimeKit only requires 10.0.0, which has advisories). `dotnet list package --vulnerable --include-transitive`: none. After the upgrade, check what still pulls in `System.Text.Json` 5.0.2
- [x] Remaining packages to current releases. **Done:** Bogus 35.5.1 → 35.6.5 (evaluation seeder), jose-jwt 5.0.0 → 5.3.0 (login tokens), QRCoder 1.5.1 → 1.8.1 (2FA setup QR). `dotnet list package --outdated`: nothing; `--vulnerable --include-transitive`: none. MailKit 4.5.0 carried a moderate advisory (NU1902); on `net10.0` the audit also reported high-severity NU1903 for `MimeKit` 4.5.0 and transitive `System.Security.Cryptography.Pkcs` 8.0.0. **Mail done:** MailKit/MimeKit 4.18.1, BouncyCastle 2.7.0, and `System.Security.Cryptography.Pkcs` 10.0.13 pinned directly (MimeKit only requires 10.0.0, which has advisories). `dotnet list package --vulnerable --include-transitive`: none. `System.Text.Json` 5.0.2 is no longer in the graph (`dotnet nuget why`: no dependency, 2026-10-23)
- [x] Warnings: CA2022 done with `ReadAtLeast(bytes, bytes.Length, throwOnEndOfStream: false)` rather than `ReadExactly`, which would throw on a short file on the licence path. ASP0019: n/a. It flags `Headers.Add` and recommends `Append` or the indexer; `Startup.cs` already uses `Append` and no ASP0019 warning is reported (the line below had it backwards). Was: CA2022 → `ReadExactly` at `FileUtil.cs:875` (**licence build-date path**: covered by the licence gate); ASP0019 → header indexer instead of `Headers.Append` at `Startup.cs:514`
- [x] **MiniProfiler. Present, not absent. Removed** (John's decision, as in Sockeye `6dd2b09`): both packages, `AddMemoryCache`/`AddMiniProfiler`/`UseMiniProfiler`, the `/profiler/results` download-token workaround in the auth middleware, the unused `using` in `ReportBiz.cs`, three commented-out `using` lines, and the credit in `docs/.../appendix-os-credits.md`. Client: `ops-profile.vue` and its route remain, but the menu entry was already commented out (`initialize.js:785`) and the page was retired after the beta (`changelog.md:519`); John may remove them. Was: `MiniProfiler.AspNetCore.Mvc` and `.EntityFrameworkCore` 4.3.8 (`AyaNova.csproj:48-49`); `AddMiniProfiler(...).AddEntityFramework()` (`Startup.cs:62-74`); auth workaround for `/profiler/results` (`Startup.cs:393-441`); `UseMiniProfiler()` (`Startup.cs:530`); `using StackExchange.Profiling.Internal` (`ReportBiz.cs:14`). Nothing in `raven-client`. Keep and upgrade, or remove: see Open questions
- [x] **BinaryFormatter.** n/a: not used anywhere in `server/AyaNova`
@@ -106,7 +106,7 @@ them. Items touching those three areas carry more weight here than they did in S
## 2. Configuration behaviour to check
- [x] **URL binding precedence.** n/a: `UseUrls(ServerBootConfig.AYANOVA_USE_URLS)` (`Program.cs:340`), read from `config.json`, environment and command line (`Program.cs:38`, `ServerBootConfig.cs:167-170`). The documented `AYANOVA_USE_URLS` is the one that wins over `ASPNETCORE_URLS`; a command-line `--urls` still overrides it through `UseConfiguration` (`Program.cs:341`)
- [x] **Logging providers.** `appsettings.json` Debug and Console levels `Trace` → `Warning`. `appsettings.Development.json` left: only read when `ASPNETCORE_ENVIRONMENT=Development`, which nothing sets. No journal flood: `Program.cs:348` calls `ClearProviders()` before `UseNLog()`. `appsettings.json:4-13` still sets the Debug and Console providers to `Trace`, with no effect today. Fix the levels in the repo
- [x] **Logging providers.** `appsettings.json` Debug and Console levels `Trace` → `Warning`. `appsettings.Development.json` left: only read when `ASPNETCORE_ENVIRONMENT=Development`, which nothing sets. No journal flood: `Program.cs:348` calls `ClearProviders()` before `UseNLog()`, so the old `Trace` levels never had an effect
- [x] **Data Protection keys.** n/a: nothing uses Data Protection; authentication is JWT only (`Startup.cs:278-302`)
## 3. Fixes found through Sockeye (each its own commit)
@@ -130,20 +130,20 @@ suite is waiting on (case 4653, case 4654, the contract issue).
## 4. Test under realistic conditions
- [x] **Database role.** Done on the Ubuntu 24.04 droplet (2026-10-23): role `"AyaNova"`, no superuser, no CREATEDB, password `p @:/?#% x`; boot, on-demand backup (818 entries), 22/22 reports and the integration suite all pass. Scheduled backup uses the same code path as on-demand. Run under a non-superuser role **named like the database**, with a password containing spaces and `@ : / ? # %`. Boot, on-demand backup, scheduled backup, restore. Sockeye ran as `postgres` for years and never exercised either bug in section 3
- [x] **Restore with a dedicated role.** Done on the droplet: `createdb --owner=AyaNova`, `pg_restore --no-owner --no-privileges --role=AyaNova`; every table owned by the role, integrity check and licence pass at boot. A plain superuser restore (`dropdb`/`createdb`/`pg_restore` as `postgres`) of an 8.2.4 dump into 8.3.0 also works. Manual comparison still to do. `createdb -O <role>`, then `pg_restore --no-owner --no-privileges --role=<role>`. Without `--role`, a superuser restore leaves every table owned by `postgres`, and the integrity check, which counts through `information_schema`, fails. Compare with the restore instructions in the customer manual (`docs/`) and note any change needed
- [x] **Restore with a dedicated role.** Done on the droplet: `createdb --owner=AyaNova`, `pg_restore --no-owner --no-privileges --role=AyaNova`; every table owned by the role, integrity check and licence pass at boot. A plain superuser restore (`dropdb`/`createdb`/`pg_restore` as `postgres`) of an 8.2.4 dump into 8.3.0 also works. Manual compared (2026-10-23): `ops-restore.md` restores as `postgres` into the existing database (`pg_restore -U postgres -c -d AyaNova …`), which is the default setup and matches the tested superuser restore; no change needed for 8.3.0. A customer with a dedicated role would need `--role` (see Deferred). `createdb -O <role>`, then `pg_restore --no-owner --no-privileges --role=<role>`. Without `--role`, a superuser restore leaves every table owned by `postgres`, and the integrity check, which counts through `information_schema`, fails. Compare with the restore instructions in the customer manual (`docs/`) and note any change needed
- [x] **Reports, all advanced reports**, compared with the baseline PDFs. Done: Windows (page counts = PuppeteerSharp 17), Ubuntu 24.04 and 26.04 droplets, 22/22 each; John checked the PDFs visually; `ldd` clean on both Ubuntu versions; no orphaned browser processes after a cancelled render. Was: On Windows and on Linux. On Linux also: `ldd` on the downloaded browser binary for missing libraries (install exactly what is reported; several Ubuntu 24.04+ names carry a `t64` suffix); the sandbox under the service account; no orphaned `chrome` processes after a cancelled render
- [x] Integration suite: same result as the baseline. Locally on every step; on both droplets with `UserWithActivityShouldNotBeDeleteable` excluded (it deletes SuperUser when SuperUser has no related records, see Deferred)
- [ ] Licence verification gate: green
- [ ] Cypress E2E (`raven-test\e2e`) against a devtest server running the .NET 10 build
- [x] Licence verification gate: green. 730/730 on 2026-10-23 at `181b1e44` (`dotnet test ayanova.tests`); re-run in the final gate (section 5)
- [ ] Cypress E2E (`raven-test\e2e`) against a devtest server running the .NET 10 build (`devtestn10` is kept for this until release, John). Also covers the UI half of "exercise LINQ-based queries screen by screen" (section 1)
- [x] `build-release.bat` produces all five packages; install and start each one: Windows standalone, Windows LAN, Linux server, Linux desktop, subscription Linux. All five built (2026-10-23, from `4a011f65`+). **Linux done** on droplet `devtestn10` (Ubuntu 24.04): subscription zip as an in-place upgrade of 8.2.4, perpetual server and desktop zips booted fresh (see log). **Windows standalone done** in Windows Sandbox (upgrade 8.2.4 → 8.3.0, uninstall, fresh install; see log); fresh install needed the `standalone.iss` PostgreSQL folder fix. **Windows LAN done** in Windows Sandbox (fresh install following the manual, see log). Re-check both Windows installers from the final release build (they carry the fixes made during this test)
## 5. Release
- [ ] **Every host that runs a framework-dependent build needs the .NET 10 runtime** before it gets the release:
- Hosted subscription droplets (Ubuntu 24.04). **Confirmed on the test droplet:** `apt-get install -y aspnetcore-runtime-10.0` gets 10.0.13 from Ubuntu's own archive (`noble-updates/main`, `noble-security/main`), no PPA. Installing it replaces `dotnet-host-8.0` with `dotnet-host-10.0` (the shared `dotnet` command); the 8.0 runtime stays installed and unused. Tested upgrade 8.2.4 → 8.3.0 in place: stop service, install runtime, the manual's file swap, start; boots and keeps the licence. 26.04: to be confirmed on the same droplet rebuilt
- Hosted subscription droplets (Ubuntu 24.04). **Confirmed on the test droplet:** `apt-get install -y aspnetcore-runtime-10.0` gets 10.0.13 from Ubuntu's own archive (`noble-updates/main`, `noble-security/main`), no PPA. Installing it replaces `dotnet-host-8.0` with `dotnet-host-10.0` (the shared `dotnet` command); the 8.0 runtime stays installed and unused. Tested upgrade 8.2.4 → 8.3.0 in place: stop service, install runtime, the manual's file swap, start; boots and keeps the licence. 26.04: confirmed on the rebuilt droplet (fresh install with the updated setup script, 2026-10-23); 8.2.4 cannot run there (no .NET 8 in 26.04)
- **Subscription server setup script** (`sockeye-client/src/views/biz-subscription-server.vue`, around lines 1350-1423; filled in per server and copied to the clipboard from the "Script" menu, used for every new subscription droplet): `apt-get install -y aspnetcore-runtime-8.0` (line 1377) → the .NET 10 runtime from whichever source the test droplet confirms; remove the `mkdir`/`chmod g+rwx` of `/var/ayanova/Chrome` and `ChromeHeadlessShell` (lines 1396-1397, 1402-1403), the browser now downloads to `/var/ayanova/data/report-browser`. Verify by running the updated script on the test droplet. Part of this port (John, 2026-10-22). Runtime and Chrome-folder change committed in `sockeye-client` `main` (2026-10-23); **do not deploy a Sockeye client built from it before 8.3.0 is released** (the script installs the released zip; 8.2.4 needs .NET 8). 26.04 support and hardening committed in `sockeye-client` `main` (`64d8f62`, 2026-10-23), tested end to end on a fresh 26.04.1 droplet: PostgreSQL via `postgresql-common`'s `apt.postgresql.org.sh` (`apt-key` is gone in newer Ubuntu); `libgdk-pixbuf2.0-0` → `libgdk-pixbuf-2.0-0` (the only library name missing on 26.04); unique random PostgreSQL password and JWT secret per server, written to PostgreSQL, `config.json` and `/root/ayanova-secrets.txt` (600); `config.json` 640 `root:www-data`; John's `52no-phasing` apt setting
- Self-hosted Linux customers (server and desktop zips are framework-dependent)
- Windows LAN: `lan.iss` prompts for the ASP.NET Core Hosting Bundle. Text and link updated to .NET 10 (2026-10-23); installer test still in section 4
- Windows LAN: `lan.iss` prompts for the ASP.NET Core Hosting Bundle. Text and link updated to .NET 10 (2026-10-23); tested in Windows Sandbox (section 4)
- Windows standalone and the launcher are self-contained: no runtime needed on the customer's machine. **But they carry the .NET runtime of the build machine's SDK:** SDK 10.0.103 → runtime 10.0.3 (the Sandbox test logged `.Net Version - 10.0.3`; Linux hosts run 10.0.13). Before the final release build, update the workstation's .NET 10 SDK to the newest release so the standalone package ships the current runtime with its security fixes. 8.2.4 did the same with .NET 8.0.13. **Done 2026-10-23:** SDK 10.0.402 installed with winget (`winget upgrade` did not find the Visual Studio-installed 10.0.103); test publish of the standalone server and the launcher bundles runtime 10.0.13. Standing note added to `devdocs/build/BUILD.md`
- [x] Customer manual (`docs/`): system requirements and upgrade instructions for self-hosted customers. Report browser move (section 3): manual already updated in the same commit (`ops-config-report-render-browser-path.md`, `ops-install-linux-server.md`, `ops-upgrade-linux-server.md`, `ops-upgrade-linux-desktop.md`). .NET 10 runtime install and upgrade steps (Windows LAN and IIS, Linux server and desktop), Ubuntu 24.04/26.04, backup password note and the 8.3.0 changelog draft: `111d7922` (2026-10-23). Changelog wording to be finalised by John before release
- [ ] Build machines: the workstation has the .NET 10 SDK (10.0.402, plus 10.0.103 from Visual Studio). The backup laptop needs it before it can build 8.3.0 (`winget install --id Microsoft.DotNet.SDK.10 -e --source winget`; the .NET 8 SDK is no longer needed); tracked with the laptop's other catch-up items in `devdocs/build/BUILD.md`. `devdocs/build/DEV-VM-SETUP.md` and `devdocs/build/BUILD.md` updated (2026-10-23). The build VM is deprecated (John, 2026-10-23): n/a
@@ -187,6 +187,7 @@ Found during the port, out of scope. One line each.
- `raven-launcher` `Program.cs:98` calls `PGProcess.StandardInput.Close()` but standard input was never redirected, so it throws `InvalidOperationException` at shutdown: the "Postgres shut down" step never runs and the launcher exits with an error when the server stops. Postgres was started detached by `pg_ctl start`, so it probably stays running. Pre-existing; candidate for its own case. **Confirmed in the Sandbox test (8.2.4 and 8.3.0):** after "Shut down server" the launcher crashes with exactly this exception and 7 `postgres` processes stay running. Every standalone upgrade then stops at Setup's "files in use" page listing PostgreSQL Server, and "automatically close the applications" fails ("Setup was unable to automatically close all applications"): the customer must end the processes or restart Windows first. One-line fix (stop PostgreSQL with `pg_ctl stop` instead of writing to its standard input). **John, 2026-10-23: own case, fixed with the "next release" cases before 8.3.0**
- **Standalone install needs the Visual C++ runtime (pre-existing, same in 8.2.4; John, 2026-10-23: own case, fixed with the "next release" cases before 8.3.0):** the bundled PostgreSQL (`local-postgres\bin\pg_ctl.exe`, `postgres.exe`) needs `VCRUNTIME140.dll`, which neither the installer nor `local-postgres` provides. A Windows without it (a new PC, Windows Sandbox) shows "pg_ctl.exe - System Error: VCRUNTIME140.dll was not found" and AyaNova never starts. Confirmed fix: copying `vcruntime140.dll`, `vcruntime140_1.dll` and `msvcp140.dll` (x64, 14.44) into `local-postgres\bin` made PostgreSQL start. Ship those three in `dist\win-x64\postgres-standalone\bin` (app-local, allowed by Microsoft's redistribution terms) rather than running `vc_redist.x64.exe` (it crashed Windows Sandbox mid-install)
- Standalone `config.json` (launcher template) has no `AYANOVA_JWT_SECRET`, so every boot logs a warning and generates a random one (logins are lost on restart). Pre-existing; noted from the Sandbox test logs. **John, 2026-10-23: own case, fixed with the "next release" cases before 8.3.0**
- Restore manual (`ops-restore.md`) covers only the default `postgres` setup. A customer running AyaNova under a dedicated, non-superuser role who restores as `postgres` without `--role` ends up with tables owned by `postgres` and a failed integrity check at boot (found in the section 4 role test). Add a short note: `pg_restore --no-owner --no-privileges --role=<role>`. Pre-existing; after the release
- **For the security review after 8.3.0:** the LAN/IIS (`dist\assets\lan-install-config.json`) and Linux server (`dist\assets\linux-server\config.json`) templates ship `AYANOVA_JWT_SECRET` set to a placeholder that is printed in the manual. The manual tells users to change it (optional on Linux), but an install that keeps it signs logins with a publicly known secret. Consider generating a random secret at install time or refusing to boot with the placeholder. Pre-existing
- Standalone and LAN installers share the same Inno Setup `AppId` (`{B2BB79DB-0690-497C-B92B-955F7B468429}`) although they are different products (`AyaNova` vs `AyaNova server`): installing one over the other would be treated as the same application. Pre-existing; not tested. Both also install to the same folder (`{autopf}\ayanova`) and use port 7575, so the two flavours could never sit side by side on one machine anyway; the shared `AppId` only changes what happens when one flavour is installed **over** the other (e.g. an evaluator moving from standalone to LAN on the same PC): Setup treats it as an upgrade of the same program. Changing either `AppId` now would make that flavour's next installer miss existing installs (second Add/Remove entry over the same folder). Standalone is thought to be used almost only for evaluation (John). **John, 2026-10-23: keep both `AppId`s as they are**; the Windows install pages now say only one type per computer, uninstall the other first (backup and restore to switch)
- Sockeye 8.1.0 has the NLog 6 archive naming problem fixed here for AyaNova: archives are `log-sockeye_NN.txt`, old `-0` to `-8` archives are never deleted, and its log viewer still sorts by name (it also filters on `ayanova.txt`, not `sockeye.txt`, so the current file is listed twice). Same fix applies: `ArchiveSuffixFormat = "-{0}"` and the date sort
@@ -236,3 +237,4 @@ Found during the port, out of scope. One line each.
| 2026-10-23 | Windows standalone installer in Windows Sandbox (clean Windows 11, `C:\temp\ayanova-sandbox\ayanova-test.wsb`, checks by `check.ps1`): 8.2.4 production installer, trial licence with sample data (John), upgrade with the 8.3.0 build, uninstall, fresh install | **8.2.4 install:** needed the Visual C++ runtime first (see Deferred; `vc_redist.x64.exe` crashed the Sandbox, the three DLLs copied into `local-postgres\bin` worked); report 10 Customer Work Order 1.6 s, `Chrome`/`ChromeHeadlessShell` in the program folder. **Shutdown:** launcher crash at `Program.cs:98`, 7 `postgres` left running (see Deferred). **Upgrade to 8.3.0:** Setup "files in use" (PostgreSQL Server ×7), automatic close failed, installer cancelled itself; after the leftover processes were gone, upgrade went through: 8.3.0 (`a223a2bc`), `net10.0`, schema 20, trial licence and data kept, PostgreSQL recovered from the unclean stop; report 10 rendered in 13.9 s with the browser download, browser in `%ProgramData%\ayanova\report-browser`; runtime `10.0.3` (see section 5). **Uninstall** (delete data: yes): `Chrome`/`ChromeHeadlessShell` removed with the program folder, data folder removed; only the hand-copied runtime DLLs left behind. **Fresh install:** failed to start PostgreSQL (missing empty folders, fixed in `standalone.iss`, see the previous row); with the fixed installer: starts first time, schema 20 created, no `Chrome` folders |
| 2026-10-23 | PostgreSQL link and version for Windows network installs | The PostgreSQL install guide linked from the LAN installer prompt and the LAN/IIS manual pages (`postgresqltutorial.com/install-postgresql/`) now fails (Cloudflare error; the site moved to a database vendor, Neon). Replaced with the official `https://www.postgresql.org/download/windows/` in `lan.iss` and both pages; prompt text "Open the PostgreSQL download page now?". `AYANOVA_BACKUP_PG_DUMP_PATH` in `lan-install-config.json` and the manual examples: PostgreSQL 16 → 18, with a note to change the number to the installed version. Changelog lines added. Docs build clean; LAN installer compiled to `C:\temp\ayanova-sandbox\ayanova-windows-x64-lan-setup-pglink.exe` for the LAN test |
| 2026-10-23 | Windows LAN installer in a fresh Windows Sandbox, following `ops-install-windows-lan.md`; installer from this branch with the PostgreSQL link fix (`ayanova-windows-x64-lan-setup-pglink.exe`) | Hosting Bundle prompt opened the .NET 10 page; .NET 10.0.13 Hosting Bundle installed (very slow in the Sandbox, normal there). PostgreSQL prompt opened `postgresql.org/download/windows/`, which links to EDB; PostgreSQL 18.6-5 installed (it installs the Visual C++ runtime itself, no Sandbox crash with vGPU off). `config.json` edited (password, own JWT secret; the Sandbox has no Notepad, edited with PowerShell). AyaNova 8.3.0 boots on .NET 10.0.13, database created at schema 20, no JWT warning, no `Chrome` folders. After licensing (John), an on-demand backup succeeded with the template's `PostgreSQL\18\bin` pg_dump path. Windows Firewall prompt on every start in the Sandbox (fresh Windows each session), expected |
| 2026-10-23 | Checklist tidy-up: older unticked items in sections 0–5 checked against current evidence | `main` = `origin/main` = `net8-baseline` in `raven` and `raven-client`; tag on both remotes. Licence gate 730/730 at `181b1e44`. No EF Core warning raised as an error in any log (local dev server, Sandbox, `devtestn10`). `System.Text.Json` 5.0.2 gone from the graph. JwtBearer 10.0.13 done. Report and E2E baselines marked waived (John); Cypress stays open in section 4 and now also covers the UI side of the EF Core screen-by-screen item. Restore manual compared: fine for the default `postgres` setup; dedicated-role note added to Deferred. Stale "still to do" remarks removed. Still open: relative date tokens (section 3, decision needed), Cypress, and the section 5 release steps |