ci: add bounded complete release gate
This commit is contained in:
parent
0a934cf578
commit
2ac054864d
11 changed files with 772 additions and 102 deletions
|
|
@ -419,9 +419,9 @@ checkpoint. Do not infer status from chat history.
|
|||
| Slice | Status | Commit(s) | Evidence/gates | Exact next action |
|
||||
|---|---|---|---|---|
|
||||
| R0 | PLAN ACCEPTED; tracking/owner assignment pending | — | Audit complete at `15539a22`; user started R1 | Track plan+audit artifacts; assign R4 owner |
|
||||
| R1 | IMPLEMENTED + REQUIRED GATES PASS; review/commit pending | — | 2026-08-18 checkpoint below; F-009/T-001 resolved in working tree | Review diff, then commit the coherent R1 checkpoint |
|
||||
| R2 | NOT STARTED; technically unblocked after R1 review/commit | — | F-010/F-014/F-019 | Start only after R1 checkpoint is accepted |
|
||||
| R3 | NOT STARTED | — | T-002–T-016; F-015/F-021/F-022/F-030 | Wait for R2 |
|
||||
| R1 | COMPLETE ON CAMPAIGN BRANCH; not yet merged | `0a934cf5` | 2026-08-18 checkpoint below; F-009/T-001 resolved and committed | Preserve while R2 runs; merge through the normal review path |
|
||||
| R2 | COMPLETE GATE CHECKPOINT; broader reproducibility work remains; commit pending | — | Checkpoint below; F-014 resolved, F-010/F-019 partially resolved | Review and commit this checkpoint, then choose locked restore/warning work or R3 |
|
||||
| R3 | NOT STARTED | — | T-002–T-018; F-015/F-021/F-022/F-030 | Wait for remaining R2 sequencing decision |
|
||||
| R4 | NOT STARTED; may run parallel | — | F-001/F-026/F-031/F-034 | Assign owner/legal provenance decision path |
|
||||
| R5 | NOT STARTED | — | F-002/F-003/F-006/F-007/F-011/F-020/F-027/F-029/F-032 | Wait for R2–R3 |
|
||||
| R6 | NOT STARTED | — | F-004/F-005/F-012/F-016/F-023/F-028 | Wait for R3/R5 |
|
||||
|
|
@ -433,8 +433,8 @@ checkpoint. Do not infer status from chat history.
|
|||
### R1 implementation checkpoint — 2026-08-18
|
||||
|
||||
**Working-tree base:** `15539a22a67f8d915d88f8b1d8126cd55eedda6e`
|
||||
**Commit:** pending; do not describe this checkpoint as merged or durable until
|
||||
the source, test, plan, and audit records are committed together.
|
||||
**Commit:** `0a934cf5` on `codex/release-stabilization`; the checkpoint is
|
||||
durable on that campaign branch but is not yet merged to `main`.
|
||||
|
||||
Implementation:
|
||||
|
||||
|
|
@ -495,9 +495,79 @@ Changed implementation/test files:
|
|||
- `src/AcDream.Launcher.Core/Launching/LauncherProcessSupervisor.cs`
|
||||
- `tests/AcDream.Launcher.Core.Tests/Launching/LauncherProcessSupervisorTests.cs`
|
||||
|
||||
Rollback before commit is the exact reverse of those two file diffs. After a
|
||||
future commit, record its hash here and use `git revert <R1-commit>` rather than
|
||||
rewriting history.
|
||||
Rollback is `git revert 0a934cf5`; do not rewrite branch history.
|
||||
|
||||
### R2 complete-gate checkpoint — 2026-08-18
|
||||
|
||||
**Working-tree base:** `0a934cf5781c003375c14af9a1f565254df0f9f9`
|
||||
**Commit:** pending; the source and evidence records must be committed together
|
||||
before this checkpoint is described as durable.
|
||||
|
||||
Implemented gate:
|
||||
|
||||
- `global.json` pins the accepted .NET 10 SDK feature band at `10.0.300` with
|
||||
`latestPatch` roll-forward and prerelease SDKs disabled. Every existing
|
||||
`actions/setup-dotnet` step now reads that file instead of floating on
|
||||
`10.0.x`.
|
||||
- `tools/run-release-gate.ps1` discovers every project under `tests/` that
|
||||
declares `Microsoft.NET.Test.Sdk` or `IsTestProject`, verifies the project is
|
||||
present in `AcDream.slnx`, restores/builds the solution, and runs each test
|
||||
assembly exactly once in its own Release process. It does not retry.
|
||||
- Restore, build, and each test process have 600/900/600-second outer bounds.
|
||||
Tests additionally use VSTest's 180-second per-test blame-hang collector with
|
||||
mini dumps. An outer timeout kills the complete process tree and reports exit
|
||||
code 124; GitHub Actions adds a 45-minute job bound.
|
||||
- Every run writes exact commands and output, one TRX per assembly, any blame
|
||||
sequence/dumps, `dotnet --info`, configured NuGet sources, commit/branch/RID,
|
||||
aggregate executed/passed/skipped/failed counts, and `SHA256SUMS.txt`.
|
||||
- `.github/workflows/release-gate.yml` runs the gate on pull requests, pushes
|
||||
to `main`, and manual dispatch on `windows-latest`, then uploads the evidence
|
||||
even when the gate fails. The focused Windows/Linux portability and Vulkan
|
||||
lanes remain separate and are no longer the only deterministic CI coverage.
|
||||
- `docs/release-gate.md` is the repository-owned local/CI runbook.
|
||||
|
||||
Test-isolation corrections, with no product behavior change:
|
||||
|
||||
- Four `MainWindowViewTests` that call `Show()` now close their window and pump
|
||||
dispatcher cleanup in `finally` on the owning Avalonia test session. The old
|
||||
tests leaked shown, thread-affine compositor state to runner teardown; no
|
||||
suite serialization or retry was added.
|
||||
- The complete gate's first evidence run correctly failed
|
||||
`RealChildStderrIsCapturedForTheProcessStartInfoPath`: its live polling helper
|
||||
briefly denied write sharing, so the final async stderr callback observed an
|
||||
`IOException` and the deliberately no-throw capture sink latched off. The
|
||||
helper now reads with `FileShare.ReadWrite | FileShare.Delete`, matching the
|
||||
production status tailer; its assertions and five-second bound are unchanged.
|
||||
|
||||
Verification:
|
||||
|
||||
- Focused `MainWindowViewTests`: 13 passed / 0 skipped / 0 failed.
|
||||
- Three fresh default-parallel whole-solution runs completed inside independent
|
||||
180-second process bounds with 12/12 TRX files and no Avalonia cleanup error:
|
||||
56.719, 56.321, and 58.506 seconds. Each reported 14,748 passed / 77 skipped /
|
||||
0 failed.
|
||||
- The stderr ProcessStartInfo test passed 25/25 fresh-process repetitions after
|
||||
the live-reader correction.
|
||||
- The actual outer-watchdog function killed a controlled fixture process tree
|
||||
at 2.107 seconds, returned 124, and left no child process.
|
||||
- The repository command `pwsh ./tools/run-release-gate.ps1` completed in
|
||||
107.337 seconds on SDK `10.0.300`, RID `win-x64`: 12 assemblies, 14,748
|
||||
executed and passed / 77 skipped / 0 failed. The evidence manifest contains
|
||||
28 verified SHA-256 entries.
|
||||
|
||||
Deliberately still open in the wider R2 slice:
|
||||
|
||||
- the 26 warnings observed by a clean recompilation, centralized compiler and
|
||||
package settings, package lock files/locked restore, and broken or unsupported
|
||||
tool-project decisions;
|
||||
- the known duplicate Core theory row and classification of the 77 skips, which
|
||||
remain R3 work; and
|
||||
- stale public headline counts, which must be corrected with the documentation
|
||||
authority work rather than hand-edited as part of this gate checkpoint.
|
||||
|
||||
Therefore this checkpoint closes F-014 on the campaign branch and the SDK part
|
||||
of F-019, and gives F-010 a truthful machine-readable count. It does not claim
|
||||
the broader R2 reproducibility slice or R3 test-quality cleanup is complete.
|
||||
|
||||
## 18. Session start protocol
|
||||
|
||||
|
|
@ -532,7 +602,7 @@ review, and cross-session ledger entry are all complete.
|
|||
|
||||
## 20. Immediate next action
|
||||
|
||||
Review the R1 diff and checkpoint evidence, then commit the source, regression
|
||||
test, plan, and audit updates together if accepted. After that, begin R2's
|
||||
pinned complete gate; assign the R4 decision owner in parallel. Do not begin
|
||||
bulk comment, artifact, or giant-file cleanup first.
|
||||
Review and commit the R2 complete-gate checkpoint, then decide whether the next
|
||||
bounded goal is the remaining R2 locked-restore/warning/toolchain work or R3's
|
||||
truthful test taxonomy. Assign the R4 decision owner in parallel. Do not begin
|
||||
bulk comment, artifact, giant-file, or unrelated cleanup first.
|
||||
|
|
|
|||
41
docs/release-gate.md
Normal file
41
docs/release-gate.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Complete Release gate
|
||||
|
||||
The default release gate is repository-owned and uses the SDK feature band in
|
||||
`global.json`:
|
||||
|
||||
```powershell
|
||||
pwsh ./tools/run-release-gate.ps1
|
||||
```
|
||||
|
||||
The command restores and builds `AcDream.slnx`, discovers every project under
|
||||
`tests/` that declares `Microsoft.NET.Test.Sdk` or `IsTestProject`, verifies
|
||||
that the solution includes it, and runs each test assembly once in a fresh
|
||||
Release process. It does not retry failures.
|
||||
|
||||
Each restore, build, and test process has an outer hard timeout. Every test
|
||||
also runs with VSTest blame-hang enabled: after three minutes in one test, the
|
||||
test host is terminated and a mini dump is collected; after ten minutes, the
|
||||
outer watchdog kills the complete `dotnet test` process tree. CI additionally
|
||||
has a 45-minute job bound.
|
||||
|
||||
Evidence is written to `artifacts/release-gate/`:
|
||||
|
||||
- `release-gate-summary.json` records the commit, branch, worktree state, SDK,
|
||||
RID, bounds, process outcomes, assembly list, and
|
||||
executed/passed/skipped/failed totals;
|
||||
- `environment.txt` records `dotnet --info`, configured NuGet sources, and the
|
||||
discovered test-project set;
|
||||
- `test-results/` contains one TRX per assembly plus any VSTest hang sequence
|
||||
and dump files;
|
||||
- `logs/` contains the exact command and complete output for every child
|
||||
process; and
|
||||
- `SHA256SUMS.txt` hashes the evidence bundle.
|
||||
|
||||
The complete gate runs on Windows because it exercises the full product and
|
||||
launcher surface. `.github/workflows/headless-portability.yml` remains the
|
||||
focused Windows/Linux portability and Vulkan evidence workflow; those jobs are
|
||||
not substitutes for the complete gate.
|
||||
|
||||
Environment-dependent tests retain their current skip behavior and are counted
|
||||
explicitly in the JSON/TRX report. Classifying or replacing those tests belongs
|
||||
to R3, not to this gate checkpoint.
|
||||
|
|
@ -178,14 +178,26 @@ external systems.
|
|||
|
||||
## Post-audit stabilization update — 2026-08-18
|
||||
|
||||
R1 has been implemented and fully gated in the current uncommitted working
|
||||
tree. The launcher child is detached under the supervisor gate and stopped,
|
||||
R1 has been implemented, fully gated, and preserved at `0a934cf5` on
|
||||
`codex/release-stabilization`. The launcher child is detached under the supervisor gate and stopped,
|
||||
unsubscribed, and disposed outside it; a deterministic captured-callback race
|
||||
test fails against the old mechanism and passes against the fix. Launcher.Core
|
||||
passes 339/339, and two fresh serialized complete Release runs each finish
|
||||
inside a 900-second hard bound with 14,748 passes / 77 skips / 0 failures.
|
||||
|
||||
This resolves F-009 technically but does not change the baseline audit's
|
||||
historical count until the coherent R1 checkpoint is reviewed and committed.
|
||||
The public-release decision remains no-go because F-001, F-002, F-014, and the
|
||||
remaining high-priority release-governance findings are untouched.
|
||||
historical count; the checkpoint is committed but not yet merged to `main`.
|
||||
|
||||
The subsequent R2 gate checkpoint pins SDK feature band `10.0.300`, adds a
|
||||
repository-owned bounded Release command and Windows CI workflow that discover
|
||||
and run all 12 test assemblies, captures TRX/log/environment/hash evidence, and
|
||||
collects mini dumps before an outer process-tree timeout. Its local evidence
|
||||
run reports 14,748 executed and passed / 77 skipped / 0 failed in 107.337
|
||||
seconds. Three additional default-parallel solution runs pass without the
|
||||
previous Avalonia compositor cleanup failure after shown test windows were
|
||||
closed on their owning session.
|
||||
|
||||
This resolves F-014 technically on the campaign branch and partially addresses
|
||||
F-010/F-019. The public-release decision remains no-go because F-001, F-002,
|
||||
the 26 clean-build warnings, unpinned package graph, and the remaining
|
||||
high-priority release-governance/test-truth findings are untouched.
|
||||
|
|
|
|||
|
|
@ -214,8 +214,8 @@ did not find an actionable exception beyond the documented classes.
|
|||
test that proves both exit-callback and disposal orders converge. Audit the
|
||||
ordinary `SystemChildProcess` wrapper for the same inversion.
|
||||
|
||||
**Post-baseline resolution checkpoint (2026-08-18, uncommitted):** the working
|
||||
tree now performs the ownership transfer and all child operations outside
|
||||
**Post-baseline resolution checkpoint (2026-08-18, `0a934cf5`):** the campaign
|
||||
branch now performs the ownership transfer and all child operations outside
|
||||
`_gate`; `OnProcessExited` obtains its optional exit code without holding that
|
||||
gate. A barrier-controlled regression captures the exit delegate before
|
||||
unsubscription and makes child disposal wait for that callback. It times out in
|
||||
|
|
@ -223,9 +223,8 @@ five seconds with the old lock shape, passes in milliseconds with the fix, and
|
|||
passed 25/25 fresh-process repetitions. Launcher.Core passes 339/339. Two
|
||||
fresh serialized complete-solution runs each finished under a 900-second hard
|
||||
bound with 14,748 passes / 77 skips / 0 failures in 1:28.822 and 1:30.241.
|
||||
F-009 remains a baseline finding until the coherent R1 checkpoint is reviewed
|
||||
and committed; the current working-tree mechanism and required gates are
|
||||
resolved.
|
||||
F-009 remains in this historical baseline, but its mechanism and required gates
|
||||
are resolved in a durable campaign-branch commit that is not yet merged.
|
||||
|
||||
## F-010 — Published build/test baseline materially overstates the portable gate
|
||||
|
||||
|
|
@ -250,6 +249,13 @@ resolved.
|
|||
Fail on unexpected skips and duplicate discovery IDs; do not hand-edit test
|
||||
totals into multiple living documents.
|
||||
|
||||
**Post-baseline gate checkpoint (2026-08-18, commit pending):** the new
|
||||
repository gate emits per-assembly TRX plus a JSON summary that distinguishes
|
||||
14,748 executed/passed cases from 77 reported skips and retains the known
|
||||
duplicate-discovery warning in the process log. This makes the complete
|
||||
portable count reproducible, but F-010 remains open until R3 classifies false
|
||||
passes/skips/diagnostics and the stale public headline claims are replaced.
|
||||
|
||||
## F-011 — Mandatory WorldBuilder inventory is an obsolete OpenGL design guide
|
||||
|
||||
- **Severity:** P1 high
|
||||
|
|
@ -341,6 +347,18 @@ resolved.
|
|||
split environment-dependent gates explicitly. Give every job a hang timeout
|
||||
and collect dumps; make the portable complete gate required before release.
|
||||
|
||||
**Post-baseline resolution checkpoint (2026-08-18, commit pending):**
|
||||
`.github/workflows/release-gate.yml` now runs the repository-owned Release gate
|
||||
on Windows for pull requests, `main` pushes, and manual dispatch. The script
|
||||
auto-discovers and verifies all 12 solution test projects, runs each once in a
|
||||
fresh bounded process, arms VSTest mini-dump collection before the outer
|
||||
process-tree watchdog, and uploads commands, logs, TRX, environment metadata,
|
||||
aggregate counts, and hashes even on failure. The exact local workflow command
|
||||
passed 14,748 executed / 77 skipped / 0 failed in 107.337 seconds; an isolated
|
||||
watchdog probe returned 124 at 2.107 seconds and left no child. F-014 is
|
||||
technically resolved on the campaign branch, pending commit/review and actual
|
||||
GitHub execution after publication.
|
||||
|
||||
## F-015 — Headline pass totals include hundreds of unexecuted test contracts
|
||||
|
||||
- **Severity:** P1 high
|
||||
|
|
@ -471,6 +489,13 @@ resolved.
|
|||
that proves a clean checkout. Keep tool-only exceptions explicit rather than
|
||||
allowing per-project drift.
|
||||
|
||||
**Post-baseline partial checkpoint (2026-08-18, commit pending):** `global.json`
|
||||
pins SDK feature band `10.0.300` with `latestPatch` roll-forward, and all five
|
||||
CI setup sites now consume that file. `docs/release-gate.md` documents the one
|
||||
complete command and its evidence. F-019 remains open: common compiler/package
|
||||
settings are still duplicated, there are no package lock files or locked
|
||||
restore, and the unsupported tool-project decisions have not been made.
|
||||
|
||||
## F-020 — The issue ledger is an unbounded mixed tracker, research log, and archive
|
||||
|
||||
- **Severity:** P1 high
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ callback. The test needs a deterministic race harness after the production
|
|||
fix; the current timing-dependent version alternates between passing in 48 s
|
||||
and hanging indefinitely.
|
||||
|
||||
**Post-baseline resolution checkpoint (2026-08-18, uncommitted):**
|
||||
**Post-baseline resolution checkpoint (2026-08-18, `0a934cf5`):**
|
||||
`DisposeAllowsAnAlreadyCapturedExitCallbackToComplete` is now the deterministic
|
||||
race harness. Explicit barriers make the fake child capture the exit delegate,
|
||||
release it from inside disposal, and wait for the callback to return. The old
|
||||
|
|
@ -401,3 +401,28 @@ regression contracts with T-011's output apparatus. When a test graduates into
|
|||
a stable contract, organize it under the owning component/behavior and retain
|
||||
the issue ID in a trait or comment; keep investigation programs in a separate,
|
||||
non-default diagnostic project.
|
||||
|
||||
### T-017 — Shown Avalonia test windows escaped their owning UI session
|
||||
|
||||
Four `MainWindowViewTests` called `window.Show()` but never closed the window.
|
||||
One default-parallel solution run then failed during Avalonia headless cleanup:
|
||||
the runner/compositor touched an object from a thread other than the one that
|
||||
owned it, even though the Launcher project passed alone. The tests now close
|
||||
shown windows and pump dispatcher cleanup in `finally` on the owning Avalonia
|
||||
session. No product code, suite serialization, or retry was added. The focused
|
||||
class passes 13/13, and three fresh default-parallel complete-solution runs pass
|
||||
all 12 assemblies in 56.719, 56.321, and 58.506 seconds.
|
||||
|
||||
### T-018 — A live stderr assertion could disable the producer it observed
|
||||
|
||||
`ReadFileEventuallyContainingAsync` used `File.ReadAllTextAsync` while the
|
||||
ProcessStartInfo stderr callbacks were still draining. Its read handle did not
|
||||
share writes. If the final callback overlapped that short read, the capture
|
||||
sink saw a sharing violation, deliberately latched into its no-throw state, and
|
||||
the test waited five seconds for a line it had itself caused to be dropped. The
|
||||
first complete repository-gate run exposed exactly that two-of-three-lines
|
||||
failure. The helper now opens a live reader with
|
||||
`FileShare.ReadWrite | FileShare.Delete`, matching the production status
|
||||
tailer; the expected lines and timeout are unchanged. The test subsequently
|
||||
passed 25/25 fresh-process runs and Launcher.Core passed 339/339 in the final
|
||||
gate.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue