docs(ci): reconcile infra/README CI runbook and workflow comment with current job model and floor (lmxopcua#723)

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-09 12:28:09 -05:00
parent 8ddf737a2a
commit 5594bc7bb9
2 changed files with 20 additions and 9 deletions
+18 -7
View File
@@ -221,9 +221,13 @@ and a real directory (LDAP) — never the dev values in this doc.
## 10. CI — Gitea Actions (`.github/workflows/v2-ci.yml`)
The one workflow (there is no `.gitea/workflows/`) runs on the Gitea act_runners `gitea-runner` /
`gitea-runner-2`: a `build` job (restore, Release build, `code-reviews/regen-readme.py --check`) and a
`unit-tests` job (the whole solution minus `Category=E2E|LiveIntegration`, trx →
`scripts/ci/assert-not-all-skipped.sh` → trx upload). Read run logs read-only with
`gitea-runner-2`. It has a single `unit-tests` job that restores and builds once (`-m:2`, restore with
`--disable-parallel`) and then tests the whole solution minus `Category=E2E|LiveIntegration` (SlowUnit
is included): the `code-reviews` README drift check, the TRX-guard fixtures, restore, Release build, a
runner-capacity log, `dotnet test` (trx), `scripts/ci/assert-not-all-skipped.sh`, then the trx upload.
A repo-wide `concurrency` group (`lmxopcua-v2-ci`, `cancel-in-progress: false`, #707) allows one active
run; an active run is never cancelled. The authoritative description of the worker model, test floor
and skip diagnostic is [`scripts/ci/README.md`](../scripts/ci/README.md). Read run logs read-only with
`tea api --login <login> /repos/dohertj2/lmxopcua/actions/runs` (then `…/runs/<id>/jobs`,
`…/jobs/<id>/logs`).
@@ -234,8 +238,11 @@ Things that are not obvious (#606):
regardless of the tests. Do not "upgrade" it back to v4.
- **`AKKA_TEST_TIMEFACTOR=3` on the test step.** The Runtime/ControlPlane actor-test harnesses
(`tests/Server/*/Harness/TestTimeFactor.cs`) feed it to `akka.test.timefactor`, which dilates every
TestKit wait (explicit durations included). The leg runs every assembly at once on the runner; a long
tail of 2–8 s presence budgets each failed about one run in eight. Local runs stay at 1.
TestKit wait (explicit durations included). The test step is also serialized (`-m:1`,
`-p:TestTfmsInParallel=false`, `scripts/ci/ci.runsettings` caps xUnit at 2 collection workers, one
VSTest process) to reduce runner contention. The timefactor was added because a long tail of 2–8 s
presence budgets once each failed about one run in eight (a dated observation, not a current rate).
Local runs stay at 1.
- **Presence vs absence.** A presence wait (`ExpectMsg`, `AwaitAssert`, a poll-until) is a ceiling and
is sized from the suites' `PresenceBudget` (15 s); an absence window (`ExpectNoMsg`, settle-then-
assert) is the assertion itself and keeps its short literal. Replace a fixed `Task.Delay` before an
@@ -243,5 +250,9 @@ Things that are not obvious (#606):
- **Never leave a script spinning.** A timed-out script is abandoned, not stopped
(`TimedScriptEvaluator`), so `while(true){}` pinned a core for the rest of the test process. Timeout
tests use a bounded wall-clock spin (`System.DateTime.UtcNow` is sandbox-allowed).
- **`MIN_EXECUTED`** (`assert-not-all-skipped.sh`) is still the default `1`; raise it once a green run
is recorded (a full run executes ~12.7k tests across ~57 trx files).
- **`MIN_EXECUTED`.** `assert-not-all-skipped.sh` defaults to `1` when the variable is unset (so a
local invocation only catches the zero-executed case), but the workflow's `assert not-all-skipped`
step overrides it with `MIN_EXECUTED: "12000"`, so the hosted gate is 12000. As a dated observation,
the verified baseline run 975 (2026-10-13) counted 14,630 executed tests across 62 trx files. The
step also prints an individual-skip diagnostic (`Results/UnitTestResult` records with outcome
`NotExecuted`); it does not affect the floor. Raise the floor as the suite grows.