release-checklist
Skill526 starsChanged 18 days agoMITView on GitHub
Pre-release checklist for PerformanceMonitor — version bumps, changelog, cloud testing, and validation (Lite + Darling; Full Dashboard and CLI Installer are deprecated and out of this process)
- Commits and pushes
31 other projects use a version of this.
Adopted by
Most recently taken up by
- TrueImmortal82/open-code-skillstheir own version, first seen Nov 8, 2026
- striderZA/OpenCodeGameStudiostheir own version, first seen Nov 4, 2026
- OneByJorah/VirtOfficetheir own version, first seen Nov 1, 2026
- juanitourquiza/shipframetheir own version, first seen Oct 23, 2026
- maximhq/bifrosttheir own version, first seen Oct 20, 2026
- OneByJorah/offivotheir own version, first seen Oct 20, 2026
Used with
Projects with it also use playtest-report, soak-test and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
CoralGameSkillplaytest-report
Generates a structured playtest report template or analyzes existing playtest notes into a structured format. Use this to standardize playtest feedback collection and analysis.
Also in 12 projects that use this
lilangMaxSkillsoak-test
Generate a soak test protocol for extended play sessions. Defines what to observe, measure, and log during long play sessions to surface slow leaks, fatigue effects, and edge cases that only appear after sustained play. Primarily used in Polish and Release phases.
Also in 9 projects that use this
lilangMaxSkillteam-live-ops
Orchestrate the live-ops team for post-launch content planning: coordinates live-ops-designer, economy-designer, analytics-engineer, community-manager, writer, and narrative-director to design and plan a season, event, or live content update.
Also in 9 projects that use this
CoralGameSkillteam-polish
Orchestrate the polish team: coordinates performance-analyst, technical-artist, sound-designer, and qa-tester to optimize, polish, and harden a feature or area for release quality.
Also in 14 projects that use this
- +4 more from lilangMax
- +4 more from CoralGame
Other versions31 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 31
- Donchitos/Claude-Code-Game-Studios★ 27ksame name
- maximhq/bifrost★ 9.4ksame name
- tsukumijima/KonomiTV★ 1.1ksame name
- nkarasiak/qgis-mcp★ 364same name
- pixel-cellar/Claude-Code-Game-Studios★ 324same name
- striderZA/OpenCodeGameStudios★ 118same name
- tranhieutt/software_development_department★ 71same name
- cenconq25/claude-code-app-studio★ 40same name
- OneByJorah/offivo★ 24same name
- OneByJorah/VirtOffice★ 24same name
21 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository5 other files it gives its agents.
- llms.txtllms.txt
- buildSkill
- duckdbSkill
- lane-ordersSkill
- maintenanceSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
37 rules. 0 are common, 26 are distinctive, and 11 are very specific to this project.
0
Common
Most of the 25 edited versions we read keep these.
26
Distinctive
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 10
Run through the full release prep checklist for PerformanceMonitor.
- Very specific: line 22
Every project in the tree inherits it, and AssemblyVersion / FileVersion / InformationalVersion derive from it at build time.
- Distinctive: line 27
Verify no other files contain hardcoded version strings that need updating.
- Very specific: line 31
Ensure CHANGELOG.md has an entry for the new version with:
- Distinctive: line 40
If the previous version's changelog entry is missing, add that too.
- Distinctive: line 67
Do NOT add internal/implementation changes — only user-facing features and behavior.
- Very specific: line 73
All schema changes MUST go through the upgrades/{from}-to-{to}/ folder — never ad hoc, never baked into base install scripts.
- Very specific: line 75
Verify each script uses IF NOT EXISTS checks for idempotency, and that any column additions in 01_install_database.sql CREATE TABLE blocks …
- Distinctive: line 79
Run a FULL rebuild and check the warnings line, not just errors:
- Distinctive: line 83
All projects must succeed with 0 Warning(s) / 0 Error(s) — the repo's bar is zero-warning, test projects included (they sit outside the …
- Distinctive: line 96
Create a resource group, logical server, and 2+ databases.
- Distinctive: line 103
Add the Azure logical server to a Darling instance (a local scratch service or an existing dogfooding instance) and let it collect 2+ …
- Distinctive: line 104
Verify against the store (psql or the web dashboard):
- Distinctive: line 114
Create an RDS SQL Server instance.
- Very specific: line 123
Add the RDS endpoint to the same Darling instance (encrypt_mode Mandatory + trust_server_certificate true — RDS serves its own CA), let it …
- Very specific: line 124
Verify: the Agent-surface collectors (running_jobs, job_history, agent_status) short-circuit as capability skips (0 rows at ~0ms, no …
- Distinctive: line 135
Check Lite's latest dev build thoroughly:
- Distinctive: line 138
Check for collector failures in the Collection Health tab
- Distinctive: line 139
Verify data is populating correctly in all tabs
- Distinctive: line 153
After publishing, repeat item 2 with the signed Setup.exe to confirm that signing changed nothing.
- Distinctive: line 155
Test the upgrade over a running prior version:
- Distinctive: line 158
Run the new release's Setup.exe (and separately test Help → About → download → restart).
- Distinctive: line 160
Elevated case: run the old version as administrator, launch the new one non-elevated → expect the *"Restart as administrator"* prompt.
- Distinctive: line 169
Run the Windows items on a disposable machine or VM, and point them at a throwaway test instance.
- Distinctive: line 185
Do the whole procedure twice: once from the last release, and once from the oldest release still supported.
- Distinctive: line 195
Every non-SUCCESS row since the restart gets read.
- Very specific: line 205
Use a machine with no prior install and no C:\ProgramData\PerformanceMonitorDarling folder.
- Distinctive: line 226
Put the outcome of (a) to (d) in the release's test record.
- Distinctive: line 230
Before cutting the release, verify the nightly build has been clean:
- Very specific: line 231
Check that the most recent nightly build completed successfully (GitHub Actions) — verify the gated legs BY NAME (build, Darling PostgreSQL …
- Distinctive: line 233
If any issues were reported and fixed, wait for a new clean nightly before proceeding
- Very specific: line 237
Do the version-bump + changelog commits on a branch off dev (e.g.
- Distinctive: line 245
Do not tag or publish until step 8 passes on the unsigned Setup.exe files from the release PR's head.
- Distinctive: line 247
After PR is merged to main:
- Very specific: line 269
Add the Darling documentation link to the Feature Docs strip on the landing page (page 13037, slug free-sql-server-performance-monitoring.
- Distinctive: line 274
Always test BEFORE merging PRs
- Distinctive: line 278
Always clean up cloud test resources after testing to avoid charges
“Common” is measured: kept by at least 6 in 10 of the 25 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Pre-Release Checklist
Run through the full release prep checklist for PerformanceMonitor. $ARGUMENTS is the target version (e.g., 3.3.0).
Scope (since v3.3.0): the Full Dashboard and the CLI Installer are DEPRECATED and OUT of this process — they ship no release artifacts and get no live install/upgrade testing here. The Darling service zip and the Linux tarball DO get live install and upgrade testing, in section 8a. They still build and their test suites still run in CI on the release event, and they inherit the single
<Version>with everything else in the tree (below). The release artifacts are: Lite (zip + Velopack Setup.exe), the Darling service zip, and the Darling Viewer Setup.exe.
Checklist
Work through each step in order. Report status as you go. If a step fails, stop and report.
1. Version Bumps
Bump <Version> in Directory.Build.props. That is the whole step — one line, one file.
Every project in the tree inherits it, and AssemblyVersion / FileVersion / InformationalVersion derive
from it at build time. Do not add any of those four elements to a csproj: ProductVersionDeclarationTests
fails the build on a second <Version> property anywhere in the tree, on a re-added derived property, and
on a workflow or script that reads a version from any path but Directory.Build.props.
Verify no other files contain hardcoded version strings that need updating.
2. CHANGELOG
Ensure CHANGELOG.md has an entry for the new version with:
- Important section if there are store/schema changes or breaking changes (Darling store migrations, PG runtime upgrades with offline windows, operator actions required post-upgrade)
- Added section for new features
- Changed section for behavior changes
- Fixed section for bug fixes
- Reference links at the bottom for all issue numbers
If a week of parallel PRs left duplicate section headers in [Unreleased] (two ### Fixed blocks from keep-both merges), consolidate them at cut time with a content-preserving script that verifies the entry-line multiset is unchanged. Never re-sort by hand: a hand re-sort can silently reorder hundreds of lines.
If the previous version's changelog entry is missing, add that too.
2a. Archive and compact the cut version
CHANGELOG.md is an index: from 3.0.0 on, each released entry is reduced to its bold title and the issues it references, and the prose lives in docs/changelog/<major>.<minor>.md. The single file had reached 2,160,009 bytes, which GitHub refuses to render. [Unreleased] keeps its full prose because that is where entries are written, so once the heading is renamed to the new version its prose has to move:
python3 tools/changelog/changelog_archive.py split # rewrites the index and the archives
python3 tools/changelog/changelog_archive.py census # the counts and hashes the CI pin reads
python3 tools/changelog/changelog_archive.py verify # counts, reference resolution, size ceilings
python3 tools/changelog/changelog_archive.py roundtrip # byte identity against the pre-split revisionsplit is idempotent — run it on an already-split tree and only the newly-released version moves. Regenerating the census is the step to remember: ChangelogIndexAndArchiveTests reads tools/changelog/archive-census.txt, so a new archive with no row there fails CI, and so does a row that no longer matches its archive.
Pre-3.0 versions are deliberately not archived: those entries carry no prose to move, and an empty file beside them would be one more thing to maintain that says nothing.
2b. README Sync
Cross-reference README.md against the changelog and ensure all user-facing changes are reflected:
- Lite collector table: New collectors added, count updated
- Lite/Darling tab lists: New tabs listed
- Edition comparison table: Collector counts, feature rows updated
- Managed platform support table: New platform behaviors documented
- Permissions section: Updated if new grants are needed
- Deprecation callout: still accurate about what ships and what doesn't
Do NOT add internal/implementation changes — only user-facing features and behavior.
3. Upgrade Scripts — Schema Change Audit (conditional)
Applies ONLY when install/ or upgrades/ changed since the last release (the deprecated Dashboard edition remains on bug-fix support, so its schema discipline still holds when it IS touched):
- All schema changes MUST go through the
upgrades/{from}-to-{to}/folder — never ad hoc, never baked into base install scripts. View-only changes flow throughCREATE OR ALTERre-runs and need no upgrade script. - List all .sql files in the upgrade folder and compare against
upgrade.txt. A script that is not listed does not run. - Verify each script uses
IF NOT EXISTSchecks for idempotency, and that any column additions in01_install_database.sqlCREATE TABLE blocks have corresponding ALTER TABLE scripts in the upgrade folder.
4. Build Verification
Run a FULL rebuild and check the warnings line, not just errors:
dotnet build PerformanceMonitor.sln -c Debug -t:RebuildAll projects must succeed with 0 Warning(s) / 0 Error(s) — the repo's bar is zero-warning, test projects included (they sit outside the WarningsAsErrors gate, so a warm incremental build can hide a warning a Rebuild surfaces).
The statement-column census test fails while any entry or watched writer is pending, in every Darling test run, with or without the variable. Run DARLING_RELEASE_CUT=1 Darling/Darling.Tests/bin/Debug/net10.0-windows/Darling.Tests.exe -method "*StatementCensus_PendingEntries_BlockARelease*" to see the list early; the cut proceeds only when it passes. The release workflow (build.yml, the "Statement filter release gate" step) runs the same test with the variable set before it publishes or packages anything, so a release cannot ship while an entry is pending even if this step is skipped; run it here first to see the list early.
(The deprecated Installer/Dashboard test suites run in CI on the release event with the CI's own filter; they are no longer run from this checklist.)
5. Cloud Platform Testing (shared collector layer — test via DARLING)
This step is never skipped for a release (defer within the release window is OK; skip is not). Lite and Darling share the collector layer (PerformanceMonitor.Collectors), so the cloud-specific collector paths — Azure SQL DB edition detection, the master/database-level fallbacks, RDS capability skips — are exercised once, through Darling, which is headless and fully scriptable (no GUI clicking). Lite is covered by the shared code plus its unit suites; run a Lite-side pass too only when a LITE-specific cloud behavior shipped this release (connection-alert flows, webhook delivery, UI surfacing of cloud rows — their authoritative validation is Lite.Tests/AzureMasterFallbackTests + ConnectionEdgeDetectorTests and the alert-policy suites).
Spin up temporary instances with the Azure CLI (az) and AWS CLI (aws):
Azure SQL DB: (export SQL_TEST_PASSWORD with a freshly generated throwaway password before running these; never hardcode one)
- Create a resource group, logical server, and 2+ databases. Use a region geographically close to the machine running the collector -- cross-country latency causes collector timeouts. From US East that is eastus or eastus2:
az group create --name rg-release-test --location eastus2 az sql server create --name pm-release-test --resource-group rg-release-test --location eastus2 --admin-user sqladmin --admin-password "$SQL_TEST_PASSWORD" az sql server firewall-rule create --resource-group rg-release-test --server pm-release-test --name AllowAll --start-ip-address 0.0.0.0 --end-ip-address 255.255.255.255 az sql db create --resource-group rg-release-test --server pm-release-test --name testdb1 --edition GeneralPurpose --compute-model Serverless --family Gen5 --capacity 1 --auto-pause-delay 60 --min-capacity 0.5 --max-size 1GB - Add the Azure logical server to a Darling instance (a local scratch service or an existing dogfooding instance) and let it collect 2+ cycles.
- Verify against the store (psql or the web dashboard):
database_size_stats/ size collectors cover ALL databases, not just master (the #1631 fallback class)- server row shows engine edition 5, and no collector that does not apply to Azure SQL DB errors. The SQL Agent collectors (
running_jobs,job_history,agent_status) are marked not applicable when the server is added (add_serversanswers "Agent surface: not applicable") and never run, so they leave nocollection_logrow and no health entry. That is the expected result, not a gap (verified v3.10.0) collection_logclean for the cloud server across the cycles- the always-on XE sessions exist in the Azure database:
PerformanceMonitor_Deadlock,PerformanceMonitor_BlockedProcessandPerformanceMonitor_Attention(the client-timeout session, #5640;SELECT name FROM sys.database_event_sessions), or this install's ownPerformanceMonitor_Darling_<id>_.../PerformanceMonitor_Lite_<id>_...fallback of the same capture.PerformanceMonitor_Attentionhas two actions that no Azure run has proved:sqlserver.client_hostnameandsqlserver.sql_text. If the create is rejected with error 25744 (The action ... is not available for Azure SQL Database), put the named action on the closed list, as #3753 did for the long-query trace, inAlwaysOnXeSessions.AttentionAzureRejectedActions(a one-line edit: the Azure DDL is generated from it), and re-run - the serverless DB's 60s auto-pause + resume (error 40613 transients) does not wedge collection — rows resume after the pause without a service restart
- Firewall churn: DELETE the allow rule, wait 3–5 minutes, re-add it. Collection must resume on its own without restarting the service. (CAVEAT, verified v3.2.0: a bare rule-deletion often does NOT sever an actively-collecting client — connection pooling keeps the open connection alive and Azure gates only NEW connections — so treat a no-outage result as inconclusive rather than a pass; the recovery logic's authoritative validation is the unit suites.) To force a real outage (verified v3.10.0): open admin sessions in each user database BEFORE deleting the rule, in case the machine you test from shares the Darling host's egress IP. Delete the rule, wait 6 minutes for it to take effect, then KILL Darling's sessions (
program_name=PerformanceMonitorDarling) from those sessions. KILL is denied in master even for the server admin, so collectors pooled on master keep running. Collectors that open new connections then hit 40615: thecollection_logmessage must name the firewall, and those collectors must store rows again after the rule is re-added, with the service'sstarted_atunchanged. - Clean up:
az group delete --name rg-release-test --yes --no-wait
AWS RDS: (same SQL_TEST_PASSWORD throwaway as above)
- Create an RDS SQL Server instance. Use a region geographically close to the machine running the collector -- cross-country latency causes collector timeouts. From US East that is us-east-1:
aws rds create-db-instance --db-instance-identifier pm-release-test --db-instance-class db.t3.xlarge --engine sqlserver-ee --master-username admin --master-user-password "$SQL_TEST_PASSWORD" --allocated-storage 20 --region us-east-1 - Network reachability is not automatic: a fresh instance answers "server was not found" until it is opened up. Verify
PubliclyAccessibleis true, and open 1433 on the instance's security group — the account-default SG has no public inbound:aws rds describe-db-instances --db-instance-identifier pm-release-test --region us-east-1 --query 'DBInstances[0].[PubliclyAccessible,VpcSecurityGroups[0].VpcSecurityGroupId]' --output text aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 1433 --cidr 0.0.0.0/0 --region us-east-1 - Add the RDS endpoint to the same Darling instance (
encrypt_modeMandatory +trust_server_certificatetrue — RDS serves its own CA), let it collect 2+ cycles. - Verify: the Agent-surface collectors (
running_jobs,job_history,agent_status) short-circuit as capability skips (0 rows at ~0ms, no errors); everything else lands rows;collection_logclean. - Clean up — the instance AND the SG hole (it is usually the account-DEFAULT security group; leaving 1433/0.0.0.0/0 on it is a standing exposure for anything else in that VPC):
aws rds delete-db-instance --db-instance-identifier pm-release-test --skip-final-snapshot --region us-east-1 aws ec2 revoke-security-group-ingress --group-id <sg-id> --protocol tcp --port 1433 --cidr 0.0.0.0/0 --region us-east-1
Success criteria: no collector errors in the store's collection_log for either cloud server, all applicable collectors landing rows, no inapplicable collector recorded as a failure (RDS records them as capability skips; Azure SQL DB never runs them).
6. Lite Collector Validation
Check Lite's latest dev build thoroughly:
- Review the Lite error log at
%LOCALAPPDATA%\PerformanceMonitorLite\logs\for any errors - Launch Lite, connect to at least one server, and monitor collector health
- Check for collector failures in the Collection Health tab
- Verify data is populating correctly in all tabs
7. Smoke Test New Features
Quick click-through of any new features or significant changes listed in the changelog — Lite, the Darling web dashboard, and the Darling Viewer.
8. Desktop App Upgrade — Velopack Setup.exe + single-instance handoff
Covers the desktop apps' own upgrade via Velopack (*-Setup.exe) for Lite and the Darling Viewer.
This step is a gate. Run it after step 10 opens the release PR and before step 11 tags the release. Run it on every release, even when the upgrade code did not change. Publishing notifies everyone who watches the repo, and the apps offer the new version in Help → About. A check after publishing finds a broken upgrade only after users can install it.
Before the cut, build each new Setup.exe from the release PR's head commit as build.yml does. Run dotnet publish for the self-contained build, then vpk download and vpk pack with the same arguments, except -p. In build.yml, -p points at the signed payload (signed/Lite-Velopack, signed/DarlingViewer-Velopack). Point it at the unsigned publish folder instead (publish/Lite-velopack, publish/DarlingViewer-velopack). These Setup.exe files are unsigned. Run each one on a clean Windows machine over the prior release's signed Setup.exe.
After publishing, repeat item 2 with the signed Setup.exe to confirm that signing changed nothing. That repeat is not the gate.
Test the upgrade over a running prior version:
- Install the prior release's Setup.exe, launch the app, and minimize it to the tray (leave it running).
- Run the new release's Setup.exe (and separately test Help → About → download → restart). Confirm the new version actually runs afterward — not the stale in-memory one.
- Single-instance upgrade handoff (#1148): with the old version running in the tray, launch the new build → expect the "A previous version is still running — close it and continue?" prompt → old closes → new takes over. A same-version relaunch should just surface the running window (no prompt). An older build launched over a newer one should surface the newer (no eviction).
- Elevated case: run the old version as administrator, launch the new one non-elevated → expect the "Restart as administrator" prompt; elevating completes the takeover. A same-version elevated instance should just surface (no UAC).
- Confirm Lite never closes the Darling Viewer and vice-versa (scoped by exe name).
Local proxy without a release: bump <Version>, rebuild, run over the old build → expect the close-and-takeover prompt. The decision logic is unit-tested (Lite.Tests/SingleInstanceDecisionTests); this step validates the live Win32/Velopack seam (SingleInstanceCoordinator / ProcessInspector in PerformanceMonitor.Ui). Design: plans/single-instance-upgrade-handoff.md.
8a. Darling service install and upgrade (every release)
Section 8 covers the desktop apps. This section covers the Darling service zip and the Linux tarball. They carry their own install and upgrade scripts, which a Velopack run never touches. A service install that works only on a clean machine is the shape that shipped broken in #5627. So none of this is optional, and the unit suites cannot stand in for it.
Run the Windows items on a disposable machine or VM, and point them at a throwaway test instance. Keep the machine-neutral rule: no local instance names, hosts or credentials in anything you record. A cloud test instance gets its throwaway SQL_TEST_PASSWORD, as in section 5.
(a) The Windows upgrade-shape CI job
The workflow is .github/workflows/darling-upgrade-shapes.yml. It runs 14 legs: seven on windows-2022 and seven on windows-2025. Each leg installs a real released build with that build's own scripts, then runs this commit's install or upgrade script over it. The legs cover four shapes:
- U1: an install on the default virtual account.
- U2: an install whose service logon was changed to a non-default local account.
- U3: an install whose service was deleted.
- U4: a pre-3.9 folder directly under
C:\that must still refuse and print the move steps.
The workflow runs on pull requests that touch Darling/tools/*.ps1, as the Darling upgrade shapes job in the nightly, and by manual dispatch. The release commit often carries no such check, so look for the run at its sha. In the release commit's checks or the nightly, confirm all 14 legs ran at that sha and are green, by name. A skipped leg is not a pass. If there is no run at that sha, start one with gh workflow run darling-upgrade-shapes.yml --ref <release branch> and wait for it.
Also read the two pins at the top of the workflow, DARLING_CURRENT_RELEASE and DARLING_OLD_RELEASE. The first must name the last shipped release, and the second a release from before 3.9 that is still downloadable. Record the run URL. If any leg is red or skipped, stop. A red leg blocks the release, and re-running it until it passes is not a fix.
(b) upgrade-darling.ps1 over a real existing install
Do the whole procedure twice: once from the last release, and once from the oldest release still supported.
- Which release is the oldest supported: the oldest
Darling/Darling.Tests/Fixtures/migration-ladder-v<version>.sqlin the tree.MigrationUpgradeLadderLiveTestsclimbs the current ladder over every fixture in that folder. ItsTheMostRecentRelease_HasALadderFixturecheck keeps the newest shipped release in the set. So the oldest fixture is the oldest store the tests vouch for. Read the folder at release time, and do not copy a version number into this file. Deleting a fixture drops that release from support, so make it a deliberate decision and not a tidy-up. - Set up the old install: download that release's Darling zip and extract it to
C:\Program Files\PerformanceMonitorDarling. Write adarling.jsonthat points at one throwaway test instance. Install it the way that release documented: itsinstall-darling.ps1, or the manual steps in the README's "Upgrading from a build that predates the script" section when that release has no script. Let it collect for at least two cycles. Before upgrading, recordMAX(version)fromdarling_schema_versionand the account the service runs as. Also record the row counts of two or threecollect.*tables. - Upgrade: extract the new release zip to a staging folder under
C:\Program Files\that only administrators can write to. From an elevated PowerShell, run that copy'supgrade-darling.ps1 -Source <staging folder>. On one of the two runs, point-Sourceat the downloaded zip with-Sha256from the release page, so the hash path runs too. When the old release predates the script, the new zip's script still runs over it, because it finds the install through the registered service. If the README still tells those users to take the manual procedure, walk that once as well. Record which path worked. - Pass, at the script: it exits 0 without a refusal. It prints that the SHA256 was verified (zip run), that
darling.jsonis byte-identical, that the install manifest was written, and "Service is Running". Pass, 10 to 15 minutes later: work the five checks the script prints against the store.
MAX(version)equals the new build's top rung.collect.collection_loghas rows for every configured server in the last 15 minutes.- The collector count is in the mid-30s, not single digits.
- Every non-SUCCESS row since the restart gets read. YIELDED is the lock-timeout guard working. Anything else is a finding.
- One table the release added or changed shows new rows.
The row counts you recorded before the upgrade must still be there, and the service account must be unchanged. A service that is Running but not collecting is a fail.
- What the tests already cover: the
*RungTestsclasses inDarling/Darling.Testspin each migration rung's SQL and probes on every build, with no database.MigrationUpgradeLadderLiveTestsreplays the current ladder over each released store on a scratch PostgreSQL, in theDarling PostgreSQL testsjob.DarlingStoreUpgradeTestsandDarlingStoreUpgradeRevertTestscover the bundled runtime swap and the in-place PostgreSQL upgrade. They use the old and new runtimes thatDarling/tools/new-upgraded-store-fixture.ps1builds, and the nightly sets that up. - What the live run adds: none of those tests runs the upgrade script or the Windows service manager. None of them sees the file ownership and permissions of an install an older build made, or a store holding real rows.
- Record: the from and to versions, the install path, and the schema version before and after. Add the five check results and the tail of the script's output.
(c) A fresh install-darling.ps1 run
Use a machine with no prior install and no C:\ProgramData\PerformanceMonitorDarling folder. Extract the release zip to C:\Program Files\PerformanceMonitorDarling and copy darling.sample.json to darling.json. Point it at the test instance, and run install-darling.ps1 from an elevated PowerShell.
Pass means three things. The pre-flight --test-connection shows PASS for each server. The service is created on its virtual account and reaches Running. The same five store checks hold after 10 to 15 minutes.
Then run uninstall-darling.ps1, with -PurgeData on a machine you will reuse, and confirm the service is gone. Record the pre-flight lines and the five check results.
(d) The Linux tarball and the container image
The release also attaches PerformanceMonitorDarling-linux-x64-<version>.tar.gz, PerformanceMonitorDarling-compose-<version>.tar.gz and SHA256SUMS-linux.txt (#6123). The darling-linux job in build.yml builds them. The tarball is a framework-dependent publish of the service, tarred with no wrapper folder. The compose archive is the Darling/compose/ folder from git in one wrapper folder, with the darling image line changed from :latest to :<version>. The darling-linux-publish job uploads them and pushes ghcr.io/erikdarlingdata/performancemonitor-darling, tagged with the version and latest. It starts only after the Windows build job has passed, signature checks included (#5804), so the Linux assets reach the release some minutes after the Windows ones; a release whose Windows build failed has no Linux assets and no new image. The tarball waits as a workflow artifact for seven days, so a "Re-run failed jobs" within a week publishes it; after that use "Re-run all jobs".
Linux has no install script, no upgrade script and no systemd unit file in the tarball. The supported shapes are in the README's "Run on Linux" section. One is the compose stack, from the compose archive. The other is the tarball extracted to /opt/darling under a unit written from the README's example, with your own PostgreSQL.
There is no scripted Linux upgrade path. An upgrade is the same manual steps as a fresh install, over an existing store. So the release must check this by hand:
- Artifacts: the tarball, the compose archive and
SHA256SUMS-linux.txtare on the release, both checksums match, and the versioned andlatestimage tags exist. - Fresh install, compose: download
PerformanceMonitorDarling-compose-<version>.tar.gzfrom the release, extract it, and bring the stack up from the folder it makes, on a fresh volume. Its compose file already names this release's own image tag (:<version>), so no edit is needed. Check that thedarlingservice'simage:line ends in:<version>, not:latest. Pass:docker compose psshows the darling container healthy (notunhealthy). The log shows the config load andPostgres store ready.collection_logfills, as in the Windows checks. - Fresh install, systemd: extract the tarball to
/opt/darlingand installlibgssapi-krb5-2. Write the unit from the README. PointDARLING_CONFIGat a config for a throwaway PostgreSQL 15+ with TimescaleDB, and start it. Pass: the unit is active and the same store checks hold. - Upgrade: repeat each shape over a store the previous release created. For compose, keep the volume and recreate the container from this release's compose archive and image. For systemd, stop the unit, move
/opt/darlingaside, extract the new tarball, keep the config, and start the unit. Pass: the service starts, the store migrates to the new top rung, and collection continues with the earlier rows still present. - Oldest supported: apply the same fixture rule as (b). If that release did not ship a Linux tarball, say so in the record and use the oldest release that did.
- Record: the same fields as (b), plus the image digest or tarball checksum you tested.
Put the outcome of (a) to (d) in the release's test record. An unchecked box blocks the tag.
9. Nightly Build Verification
Before cutting the release, verify the nightly build has been clean:
- Check that the most recent nightly build completed successfully (GitHub Actions) — verify the gated legs BY NAME (
build,Darling PostgreSQL tests); a green wrapper exit code is not evidence, and the nightly publishes assets even when the test leg fails - Confirm no community bug reports against the nightly in the last 24-48 hours
- If any issues were reported and fixed, wait for a new clean nightly before proceeding
10. Commit and PR
- Do the version-bump + changelog commits on a branch off
dev(e.g.release/v{version}) — NEVER commit directly todevormain(branch protection) - Push the branch and merge it into
devfirst (open that PR with basedev) - Then open the release PR from
devtomain— the head MUST bedev.check-pr-branch.ymlrejects any PR tomainwhose head is notdev, so arelease/*→mainPR fails CI (the "all jobs failed" email) - Merge the
devtomainrelease PR with Create a merge commit, never squash. A squash leavesdev's commits out ofmain's history, so the next release PR conflicts on every filedevchanged. 3.10.0 was squashed, and the 3.11.0 release PR could merge only aftermainwas merged intodevwith a merge commit (#6485). An admin merge does not get past a conflict. - At release-PR merge time, dev must equal the sha the field validation ran against (or the delta must be explicitly accepted)
11. Tag and Release
Do not tag or publish until step 8 passes on the unsigned Setup.exe files from the release PR's head. Publishing notifies watchers, so every check that can block the release runs before it.
After PR is merged to main:
git checkout main && git pull
git tag v{version}
git push origin v{version}Then create the GitHub Release from the tag — build.yml triggers on release: [published] only (NOT created, and NOT on tag push alone). Publish a real release; do not use --draft (a draft fires only created, so the build/sign workflow won't run):
gh release create v{version} --title "v{version}" --notes "See CHANGELOG.md for details."The build workflow will then run, compile all artifacts, sign them (if SignPath is configured), and attach them to the release. Monitor at https://github.com/erikdarlingdata/PerformanceMonitor/actions
SignPath blocks on five approval requests: Lite (zip), Darling (service + viewer apphost exes), Lite (Velopack), Darling Viewer (Velopack), and the executables Velopack generates — the Dashboard/Installer signing steps left with their artifacts. The fifth (#3288) comes after vpk pack and carries both products in one request: each Setup.exe, and the root launcher and Update.exe inside each Portable.zip. It uses the SignTemplate artifact configuration, whose **/*.exe and **/*.dll includes both need min-matches="0" because the batch contains no dll. Two executables per product stay unsigned by design and only inside the .nupkg — lib/app/<App>_ExecutionStub.exe and lib/app/Squirrel.exe — because releases.<channel>.json records that package's SHA256 and the delta patches against those bytes; the release guard allowlists exactly those, keyed on the container as well as the path. The Darling artifact-configuration slug on signpath.io signs the two apphost exes (PerformanceMonitor.Darling.Service.exe at the root and viewer/PerformanceMonitor.Darling.Viewer.exe) and leaves the PerformanceMonitor.* / third-party dlls and pg-runtime.zip alone; if it ever goes missing the single Sign Darling step fails the release. The Darling zip (PerformanceMonitorDarling-{version}.zip — service at root with pg-runtime.zip beside the exe, viewer in viewer\) joins the release assets; the pg-runtime build downloads ~340MB on a cold cache (cached across re-releases on the fetch script's content hash). Verify the Darling zip is attached and listed in SHA256SUMS.txt, alongside the Lite zip/Setup.exe and the Viewer Setup.exe.
12. Publish the Darling docs to erikdarling.com (after the tag)
The site pages describe the latest release, never dev. Run this once the tag exists and the release build has finished. tools/docs-site/README.md has the details.
- From a checkout that has the tag, run
python tools/docs-site/publish_darling_docs.py --ref v{version} --credentials <the WordPress credentials file named in your local notes> --status publish. It creates or updates thedarling-docspage and its children fromdocs/darling/at the tag. Re-running is safe: it finds each page by slug and parent. - Open two of the new pages (the parent
darling-docsand one child such asinstall). Check that the first line namesv{version}, that the links go to sibling pages and not to.mdfiles, and that a table and a code block look right. - Add the Darling documentation link to the Feature Docs strip on the landing page (page 13037, slug
free-sql-server-performance-monitoring; never change that slug). Read the page withcontext=editfirst and change only the strip. - Submit the new URLs to IndexNow:
POST /wp-json/rankmath/v1/in/submitUrlswith{"urls": "<the page URLs, one per line>"}.
Notes
- Always test BEFORE merging PRs
- Test across the supported SQL Server version range (2016 SP2 through 2025; 2017 needs CU3 or later). A machine with local instances for this lists them in the repo local CLAUDE.md, along with any that hold real data and must not be written to. Connect via pre-configured sqlcmd contexts so no credentials appear in this file or in any command it runs.
- NEVER use Express edition for cloud test instances — Express does not support SQL Agent, and several collectors need Agent surface area
- Azure CLI (
az) and AWS CLI (aws) are both available for creating/destroying test instances - Always clean up cloud test resources after testing to avoid charges
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

