Test Log Levels — Warning Only

Unit and CI test runs write Warning and above, and nothing below it (maintainer, 2026-10-26: "unit and CI test runs: warning only"). There is no Information allow-list for tests: a test that needs a lower-level line captures that logger itself.

Where the rule lives

In the two shared sinks of test/MeshWeaver.Fixture — XUnitLogger (every host built by a HostBuilder: an Orleans silo, its client, every hub inside them) and XUnitFileLogger (the TestBase container). Both resolve their level from configuration as before and then apply TestLogLevel.Resolve, which raises anything below Warning to Warning.

Why a floor and not a default. The test appsettings.json files were already Warning, and the sinks still wrote Information, because both fell back to Information when the host they served had no Logging section — and an Orleans TestCluster silo host has none. Measured on core CI run 40411029765, shard 0: 18,434 info, lines in a 39,050-line job log, against 56 at Warning or above (MeshWeaver.Data.Workspace content-type registration 3,704, [QUIESCE-START] 1,957 and [QUIESCE-OK] 1,935 per hub disposal, Orleans.Runtime.SiloOptionsLogger 840). A default can be overridden by any of the dozens of places a test host is composed; a floor in the sink cannot.

The plugin gate (tools/MeshWeaver.PluginTester) follows the same rule: its Information raises (bake-seed, the recycle-attribution categories) are on only under MW_LOG_LEVEL=Information or lower. Measured on Plugins CI run 40409265629, gate shard 1/3: 774 of 2,943 job-log lines were those raises on a green run.

A test that asserts on a lower-level line

It never goes through the shared sinks. It adds its own ILoggerProvider and opts the one category in with a LoggerFilterRule (or AddFilter<TProvider>) — the shape LateNackReenqueueCorrelationTest already uses. The floor does not touch a provider the test owns, and ILoggerFactory.CreateLogger(x).IsEnabled(level) still answers true when any provider wants the level.

The fault sink (TestTraceLog.AppendFault) is Warning-and-above by construction and unaffected.

Reading Information locally

Set MW_TEST_LOG_LEVEL=Debug (or Information) in your shell before dotnet test. Never in CI and never in a committed file — that would be the allow-list the rule forbids.

The explicit setting REPLACES the floor rather than feeding it (TestLogLevel.Resolve(configured, override) returns the override when one is set), and it also reaches the LoggerFactory: TestLogLevel.ApplyOverride adds a category-less rule for each shared sink's provider, and a provider-specific rule beats every provider-less rule in the factory's selection — so the shared appsettings.json's "MeshWeaver": "Warning" cannot filter Debug out before the sink sees it. A floor alone could only ever raise the level, which left the switch a no-op (Copilot on #7285); TestLogLevelOverrideTest pins both halves. For the plugin gate the switch is MW_LOG_LEVEL, as before.

Production is a different rule

A deployed portal is Default: Warning plus a short, declared Information allow-list of the categories operators read (the image's appsettings.json in MeshWeaver.Plugins, held by ShippedLoggingLevelsGuard). Tests have no operator reading them live, so they get no allow-list.