Some checks failed
Headless portability / portable-headless (windows-latest) (push) Failing after 42s
Headless portability / portable-launcher (windows-latest) (push) Failing after 4s
Complete Release gate / Complete Release suite (Windows) (push) Failing after 25s
Headless portability / portable-headless (ubuntu-latest) (push) Failing after 13s
Headless portability / portable-launcher (ubuntu-latest) (push) Failing after 1s
Headless portability / linux-graphical (push) Failing after 1s
Headless portability / linux-vulkan (push) Failing after 8s
691 lines
34 KiB
Markdown
691 lines
34 KiB
Markdown
# Release stabilization and human-maintainability campaign
|
||
|
||
**Status:** PROPOSED — plan recorded; implementation not started
|
||
**Created:** 2026-08-18
|
||
**Audit baseline:** `15539a22a67f8d915d88f8b1d8126cd55eedda6e`
|
||
**Evidence:** [`../reviews/2026-08-17-release-maintainability-audit.md`](../reviews/2026-08-17-release-maintainability-audit.md)
|
||
**Findings:** [`../reviews/findings-ledger.md`](../reviews/findings-ledger.md)
|
||
**Coverage proof:** [`../reviews/coverage-ledger.md`](../reviews/coverage-ledger.md)
|
||
|
||
## 1. Goal
|
||
|
||
Prepare acdream for a responsible public release and for maintenance by human
|
||
developers who do not have access to prior AI conversations, private worktrees,
|
||
or campaign memory.
|
||
|
||
The campaign succeeds when a new maintainer can clone the repository, identify
|
||
the current architecture and supported release, reproduce the build and test
|
||
gate, understand why non-obvious retail behavior exists, and publish or roll
|
||
back an authenticated release using repository-owned instructions.
|
||
|
||
This is a stabilization program, not a rewrite. The existing Runtime/App/
|
||
Headless architecture remains the foundation unless a slice proves a specific
|
||
boundary is wrong.
|
||
|
||
## 2. Binding principles
|
||
|
||
1. **Protect behavior before cleanup.** Establish a deterministic complete gate
|
||
before broad refactors, comment cleanup, or file decomposition.
|
||
2. **Distill knowledge; do not erase it.** No note, comment, issue history,
|
||
diagnostic, capture, or raw artifact is removed until its durable value has
|
||
a verified destination.
|
||
3. **One current truth.** Stable architecture and release state must not depend
|
||
on choosing between README, roadmap, milestone, campaign, memory, or
|
||
tool-specific instruction copies.
|
||
4. **Separate evidence from contracts.** Source comments explain the current
|
||
invariant. Dated research records preserve investigation history. Raw
|
||
captures live in an explicit artifact tier.
|
||
5. **No count-only gates.** A test total is meaningful only when the report says
|
||
which hermetic, installed-DAT, live, visual, manual, and diagnostic lanes
|
||
actually ran.
|
||
6. **Bound every external interaction.** Process waits, network operations,
|
||
test runs, and release steps require timeouts, cancellation, and diagnostic
|
||
artifacts on failure.
|
||
7. **Small reversible slices.** Each slice gets focused tests, a complete gate,
|
||
a reviewable commit, a rollback description, and a plan-ledger update.
|
||
8. **No opportunistic feature work.** New gameplay features wait unless needed
|
||
to prove or repair a release blocker.
|
||
|
||
## 3. Knowledge-preservation protocol
|
||
|
||
Every cleanup candidate is classified before it moves:
|
||
|
||
| Class | Durable value | Destination |
|
||
|---|---|---|
|
||
| Current invariant | Required behavior, ordering, ownership, threading, or retail rule | Short source comment and/or maintained architecture contract |
|
||
| Decision rationale | Alternatives considered, failed attempts, tradeoffs, gate outcome | Dated decision/research record linked from the current contract |
|
||
| Reproducible evidence | Minimal fixture, retail symbol/address, script, checksum, expected result | Versioned fixture/research record in Git |
|
||
| Raw evidence | Large logs, captures, Ghidra state, screenshots, dumps | Approved versioned artifact store with manifest, hash, provenance, and retention policy |
|
||
| Superseded or incorrect claim | Historically useful but no longer operative | Marked `SUPERSEDED` with successor link; archive after references are migrated |
|
||
| Duplication/noise | Repeats a preserved fact and adds no independent evidence | Delete only after destination/link validation |
|
||
|
||
Before deleting or rewriting historical material, all of these must be true:
|
||
|
||
- its current invariant is recorded at the owning code or architecture seam;
|
||
- useful retail provenance, failed approaches, and acceptance evidence remain
|
||
searchable under stable identifiers;
|
||
- inbound links and source comments point at the surviving destination;
|
||
- any raw artifact has an approved distribution, privacy, and licensing status;
|
||
- the replacement was reviewed by someone other than its author;
|
||
- the complete gate passes after the move.
|
||
|
||
Git history alone is not the preservation mechanism. History may later be
|
||
rewritten to remove large or legally restricted artifacts.
|
||
|
||
## 4. Campaign dependency map
|
||
|
||
```text
|
||
R0 baseline/authority
|
||
-> R1 launcher deadlock
|
||
-> R2 reproducible complete gate
|
||
-> R3 truthful test lanes
|
||
-> R5 documentation authority
|
||
-> R6 dead surfaces and tools
|
||
-> R7 plugin/config hardening
|
||
-> R8 bounded decomposition
|
||
-> R10 release candidate
|
||
|
||
R4 licence/provenance/release governance ---------------------> R10
|
||
R9 artifact migration (depends on R4 decisions) --------------> R10
|
||
```
|
||
|
||
R4 starts in parallel because it requires owner/legal decisions. It blocks a
|
||
public release but does not block the technical safety work in R1–R3.
|
||
|
||
## 5. Slice map
|
||
|
||
| Slice | Outcome | Depends on | Release blocking |
|
||
|---|---|---|---|
|
||
| R0 | Baseline and durable campaign authority accepted | — | yes |
|
||
| R1 | Launcher shutdown lock inversion fixed and deterministic | R0 | yes |
|
||
| R2 | Pinned clean build and complete bounded CI gate | R1 | yes |
|
||
| R3 | Test results truthfully distinguish executed, skipped, and diagnostic work | R2 | yes |
|
||
| R4 | Licence, provenance, credential disclosure, and release ownership decided | R0; parallel | yes |
|
||
| R5 | One current documentation authority; public docs match the product | R2–R3 | yes |
|
||
| R6 | Dead presentation/backend/probe surfaces removed; supported tools reproducible | R3–R5 | normally yes |
|
||
| R7 | Plugin compatibility/lifetime and diagnostic configuration hardened | R3 | yes for advertised plugin release |
|
||
| R8 | Highest-risk giant owners decomposed only at proven seams | R3, R6–R7 | selective |
|
||
| R9 | Large/generated research artifacts moved under an approved policy | R4 | yes if repository is distributed |
|
||
| R10 | Clean-clone release candidate and rollback rehearsal | all blocking slices | yes |
|
||
|
||
## 6. R0 — Baseline and authority
|
||
|
||
### Work
|
||
|
||
- Review and accept this plan and the six documents under `docs/reviews/`.
|
||
- Record the exact starting commit, SDK, package sources, operating systems,
|
||
supported release platforms, and current external prerequisites.
|
||
- Decide who owns legal/provenance decisions, CI/release credentials, and final
|
||
release approval.
|
||
- Pause unrelated feature campaigns until R1–R3 establish the safety net.
|
||
- Preserve the audit baseline before any cleanup; do not rewrite artifact
|
||
history in this slice.
|
||
|
||
### Exit criteria
|
||
|
||
- Plan and audit artifacts are tracked in the repository.
|
||
- One named owner exists for technical release approval and one for
|
||
licensing/provenance approval; the same person may hold both roles.
|
||
- The ledger in §17 identifies R1 as the only active implementation slice.
|
||
|
||
## 7. R1 — Fix the launcher shutdown deadlock first
|
||
|
||
### Confirmed failure
|
||
|
||
`LauncherProcessSupervisor.Dispose` currently holds the supervisor `_gate`
|
||
while disposing a child. `WindowsSystemChildProcess.Dispose` enters
|
||
`System.Diagnostics.Process.Dispose`; concurrently, the process-exit callback
|
||
can enter `OnProcessExited` and try to publish state through the same supervisor
|
||
gate. The captured wait cycle is:
|
||
|
||
```text
|
||
shutdown: supervisor _gate -> Process internals
|
||
exit callback: Process internals -> supervisor _gate
|
||
```
|
||
|
||
The complete solution test process hangs on
|
||
`ANullStderrLogPathBehavesExactlyAsBeforeForBothChildProcessKinds`; the
|
||
Launcher.Core project can pass alone because the race timing changes.
|
||
|
||
### Design constraints
|
||
|
||
- Never call child/process operations that may wait, dispose, raise callbacks,
|
||
or execute external code while holding `_gate`.
|
||
- Under `_gate`, make only the minimal state transition and snapshot the exact
|
||
children/work to retire.
|
||
- Perform unsubscribe, stop, kill, wait, and dispose work outside `_gate`.
|
||
- Exit callback and explicit disposal must converge idempotently regardless of
|
||
which arrives first.
|
||
- Preserve exact terminal-state ordering, status publication, graceful-stop
|
||
behavior, and child ownership; do not solve the hang by dropping callbacks.
|
||
- A failed cleanup must remain observable without starving later cleanup.
|
||
|
||
### Required tests
|
||
|
||
- Add a barrier-controlled race test that deterministically pauses the child
|
||
exit callback while disposal begins. Do not use `Thread.Sleep` as the oracle.
|
||
- Cover exit-before-dispose, dispose-before-exit, simultaneous exit/dispose,
|
||
repeated dispose, stop timeout/kill fallback, and callback failure.
|
||
- Assert one terminal publication, no resurrection, no orphan child, no held
|
||
supervisor lock during process disposal, and bounded completion.
|
||
- Run the focused race test repeatedly after its deterministic single pass.
|
||
- Run all Launcher.Core tests.
|
||
- Run the complete Release solution twice in fresh processes under a documented
|
||
timeout and retain hang dumps if either run fails to terminate.
|
||
|
||
### Exit criteria
|
||
|
||
- No process/child disposal occurs under the supervisor gate.
|
||
- The deterministic race test fails against the baseline mechanism and passes
|
||
against the fix.
|
||
- Two complete bounded solution runs finish with zero failures.
|
||
- F-009 and T-001 receive exact fix commit and gate evidence.
|
||
|
||
## 8. R2 — Reproducible build and complete CI gate
|
||
|
||
### Work
|
||
|
||
- Pin the accepted .NET 10 SDK feature band in `global.json`.
|
||
- Centralize common compiler/analyzer settings and package versions; enable
|
||
locked restore for release/CI.
|
||
- Eliminate all 26 clean-rebuild test warnings or make a narrowly justified,
|
||
centrally documented exception fail-safe.
|
||
- Build every supported product and every supported tool from a clean checkout.
|
||
- Make CI run the complete solution, not only portability subsets. Give each
|
||
project/process a timeout and collect test logs plus managed dumps on hangs.
|
||
- Preserve focused Windows/Linux portability lanes, but do not represent them
|
||
as the complete gate.
|
||
- Record restore sources, SDK/runtime, RID, commit, executed/skipped counts, and
|
||
artifact hashes in every release report.
|
||
|
||
### Exit criteria
|
||
|
||
- A clean clone restores and builds with the pinned toolchain and no warnings.
|
||
- Complete CI runs every default release test project and fails on timeout.
|
||
- The launcher hang cannot silently consume the CI job indefinitely.
|
||
- Package resolution and the gate command are reproducible from repository
|
||
instructions alone.
|
||
|
||
## 9. R3 — Make test reporting truthful
|
||
|
||
### Required lanes
|
||
|
||
1. **Hermetic release lane:** default CI; unavailable local data is never a
|
||
silent passing return.
|
||
2. **Installed-DAT/prepared-package lane:** explicit prerequisites and per-suite
|
||
skip identity; result published separately.
|
||
3. **Live/connected/visual/listening lane:** operator-owned, dated evidence;
|
||
never counted as ordinary unit coverage.
|
||
4. **Diagnostic/manual lane:** probes, dumps, fixture generators, and
|
||
characterization programs invoked explicitly outside default test totals.
|
||
|
||
### Work
|
||
|
||
- Replace the 271 asset/environment empty-return tests with explicit lane
|
||
requirements, truthful skips, or hermetic fixtures.
|
||
- Move or give stable assertions to the 51 output-only diagnostic methods.
|
||
- Delete/replace the three confirmed useless entire cases and the tautological
|
||
assertions catalogued in the audit.
|
||
- Remove the duplicate theory row and make the clean rebuild warning-free.
|
||
- Remove or re-home at least 52 tests with the unreachable panel stack.
|
||
- Retire temporary source-shape freezes once a semantic architecture/behavior
|
||
guard exists; retain whole-tree dependency guards that express real rules.
|
||
- Assign and stabilize the seven documented load-sensitive tests. Do not hide
|
||
them with generic retries.
|
||
- Inject controllable time into double-click and real-time transport tests.
|
||
|
||
### Exit criteria
|
||
|
||
- Default test success means every discovered default contract executed.
|
||
- Reports give exact reasons and prerequisite identity for every skip.
|
||
- Diagnostics and manual generators do not inflate release regression totals.
|
||
- No known duplicate row, literal tautology, or permanent empty scaffold remains
|
||
in the default suite.
|
||
|
||
## 10. R4 — Licence, provenance, security, and release ownership
|
||
|
||
This slice requires explicit project-owner decisions and, where appropriate,
|
||
qualified legal review. The implementation agent records evidence but does not
|
||
invent a redistribution basis.
|
||
|
||
### Work
|
||
|
||
- Select the project licence and establish contributor/code ownership.
|
||
- Audit WorldBuilder-derived code, dependency notices, named-retail/decompiler
|
||
exports, PDB-derived data, Ghidra databases, captures, images, and DAT-derived
|
||
fixtures for provenance and redistribution status.
|
||
- Decide which research artifacts may be public, private, regenerated, or
|
||
deleted from distributable history.
|
||
- Add SECURITY, CONTRIBUTING, changelog/version authority, disclosure and
|
||
deletion behavior for plaintext launcher credentials, and a vulnerability
|
||
response path.
|
||
- Define release artifact contents, supported platforms, SBOM/provenance,
|
||
signing/attestation policy, checksums, update manifest generation, rollback,
|
||
and release approval.
|
||
|
||
### Exit criteria
|
||
|
||
- Publicly distributed source and artifacts have an approved licence and
|
||
complete notices/provenance inventory.
|
||
- Users are told exactly how credentials are stored and removed.
|
||
- The launcher updater's production manifest and archives are generated and
|
||
verified by a repository-owned release process.
|
||
|
||
## 11. R5 — One current documentation authority
|
||
|
||
### Work
|
||
|
||
- Correct public README claims to the actual Vulkan-only client and retained UI.
|
||
- Make `docs/README.md` stable navigation plus a generated current-status block
|
||
sourced from one structured milestone/release ledger.
|
||
- Keep architecture documents limited to durable boundaries, ownership,
|
||
threading/lifetime, and data flow. Move commit/test-count/rollback chronology
|
||
to dated closeout records.
|
||
- Replace duplicated `AGENTS.md`/`CLAUDE.md` product truth with one maintained
|
||
tool-neutral source and generated thin adapters; fail CI on drift.
|
||
- Mark every memory/plan/spec as current, active, superseded, or historical.
|
||
- Normalize active issue/divergence indexes and validate their IDs, statuses,
|
||
paths, and links mechanically.
|
||
- Apply the knowledge-preservation protocol before shortening any campaign or
|
||
issue record.
|
||
|
||
### Exit criteria
|
||
|
||
- A new maintainer receives the same current answer from README, documentation
|
||
map, architecture, milestone/status ledger, and agent instructions.
|
||
- No current authority links missing private `claude-memory`, absent skills, or
|
||
developer-local paths.
|
||
- Historical records remain searchable but cannot override current truth.
|
||
|
||
## 12. R6 — Dead surfaces, diagnostics, and tools
|
||
|
||
### Work
|
||
|
||
- Decide and then remove or explicitly support the unreachable
|
||
`IPanelRenderer`/old panel stack and its tests.
|
||
- Remove stale OpenGL/framebuffer/ImGui apparatus and failed temporary-cleanup
|
||
markers from shipping assemblies after preserving useful evidence.
|
||
- Stop including the smoke plugin in release output by default.
|
||
- Classify every tool/script as supported, diagnostic, research-only, or
|
||
archived. Repair the five broken C# tools chosen as supported; remove
|
||
developer-home/old-worktree paths and document exact prerequisites.
|
||
- Centralize environment/diagnostic configuration at composition roots.
|
||
|
||
### Exit criteria
|
||
|
||
- Shipping assemblies and package contents contain no abandoned presentation
|
||
backend or sample plugin by accident.
|
||
- Every supported tool builds from the pinned clean checkout.
|
||
- Research-only tools are clearly invoked outside the release build.
|
||
|
||
## 13. R7 — Plugin and configuration contracts
|
||
|
||
### Work
|
||
|
||
- Enforce supported plugin API versions before loading code.
|
||
- Implement manifest dependencies or remove the unsupported promise.
|
||
- Publish/version `AcDream.Plugin.Abstractions` if plugins are advertised.
|
||
- Report registration cleanup and callback failures without preventing
|
||
best-effort teardown; prove collectible load-context release under failures.
|
||
- Replace absent/null allow-list ambiguity with one explicit production default.
|
||
- Replace direct hot-path environment reads/process-static mutable diagnostics
|
||
with immutable session-scoped configuration and typed sinks.
|
||
|
||
### Exit criteria
|
||
|
||
- An incompatible plugin fails before activation with an actionable message.
|
||
- Disable/dispose reports all cleanup failures and cannot silently retain host
|
||
registrations.
|
||
- Graphical and headless hosts have the same documented plugin/config default.
|
||
|
||
## 14. R8 — Bounded structural decomposition
|
||
|
||
This slice begins only after R1–R3. File size alone does not authorize a split.
|
||
|
||
### Priority candidates
|
||
|
||
- `RuntimeSetPositionState`
|
||
- `TransitionTypes`
|
||
- `RetailUiRuntime`
|
||
- `LiveEntityRuntime`
|
||
- `WorldSession`
|
||
- `WbDrawDispatcher`
|
||
|
||
### Rules
|
||
|
||
- Identify one ownership/lifetime or pure-algorithm seam at a time.
|
||
- Preserve a single state owner; do not replace a large class with mirrored
|
||
mutable state or a service graph of aliases.
|
||
- Prefer partial-file navigation when a state machine must remain one owner.
|
||
- Establish behavior/sabotage tests before extraction and remove corresponding
|
||
temporary source-text freezes afterward.
|
||
- Replace Chorizite/GL vocabulary in prepared-content DTOs with versioned
|
||
acdream-owned semantics at a separately reviewed boundary.
|
||
|
||
### Exit criteria
|
||
|
||
- Each extraction reduces change coupling or improves ownership clarity; line
|
||
count reduction alone is not success.
|
||
- Runtime behavior, retail evidence, allocations, and teardown ledgers remain
|
||
equivalent under the relevant focused and complete gates.
|
||
|
||
## 15. R9 — Repository artifact migration
|
||
|
||
### Work
|
||
|
||
- Inventory the approximately 575 MiB of Ghidra state, 299 MiB research tree,
|
||
and 151 MiB tracked logs by provenance, sensitivity, reproducibility, and
|
||
ongoing value.
|
||
- Keep compact fixtures, scripts, tool versions, summaries, and checksums in
|
||
Git. Move approved raw bundles to a versioned artifact store.
|
||
- Add a manifest/bootstrap command that verifies artifact identity.
|
||
- Define retention, redaction, access, and backup policy.
|
||
- Treat Git-history rewriting as a separately approved migration with backup,
|
||
contributor coordination, remote replacement, and verification. Never do it
|
||
as an incidental cleanup command.
|
||
|
||
### Exit criteria
|
||
|
||
- A normal clone contains what build/test/maintenance requires without opaque
|
||
generated databases or raw logs.
|
||
- Authorized researchers can retrieve exact approved evidence by manifest and
|
||
hash.
|
||
- Restricted or non-redistributable material is absent from public history.
|
||
|
||
## 16. R10 — Release-candidate gate
|
||
|
||
From a fresh clone on every supported release platform:
|
||
|
||
- restore with the pinned, locked toolchain;
|
||
- build every shipped product and supported tool with zero warnings;
|
||
- run the complete hermetic test lane with no failures, silent no-ops, hangs,
|
||
or generic retries;
|
||
- run and report the applicable DAT, connected, visual/listening, updater,
|
||
installer, graceful-shutdown, and rollback gates;
|
||
- generate versioned per-RID packages, plugin abstraction package if supported,
|
||
SBOM/provenance/checksums, and updater manifest;
|
||
- install/update/rollback using only public release instructions;
|
||
- verify package contents contain no credentials, developer paths, smoke
|
||
plugin, raw probes, or unapproved research artifacts;
|
||
- obtain technical and licensing/provenance approval.
|
||
|
||
Public release remains **NO-GO** until every blocking slice is closed.
|
||
|
||
## 17. Cross-session execution ledger
|
||
|
||
This table is the resume authority. Update it in the same commit as every slice
|
||
checkpoint. Do not infer status from chat history.
|
||
|
||
| Slice | Status | Commit(s) | Evidence/gates | Exact next action |
|
||
|---|---|---|---|---|
|
||
| R0 | PLAN ACCEPTED; R4 OWNER DECISION DEFERRED | — | Audit complete at `15539a22`; user completed R1–R3 | Retain the plan and audit artifacts as campaign authority |
|
||
| R1 | COMPLETE; MERGE AUTHORIZED 2026-08-18 | `0a934cf5` | 2026-08-18 checkpoint below; F-009/T-001 resolved and committed | Merge with the complete R1–R3 stabilization branch |
|
||
| R2 | COMPLETE; MERGE AUTHORIZED 2026-08-18 | `2ac05486`, `c38f6b88` | Checkpoints below; F-014/F-019 resolved, F-010 machine-readable, supported .NET tool portion of F-004 resolved | Merge with the complete R1–R3 stabilization branch |
|
||
| R3 | COMPLETE; MERGE AUTHORIZED 2026-08-18 | `14d371a0`, `b64c8041` | Final inventory: 1,254 files, 11,414 attributed methods, 22 approved source readers; Release gate: 14,346/14,346 | Merge the stabilization branch; retain the closeout ledger as authority |
|
||
| R4 | DEFERRED BY USER FOR FRIEND-ONLY RELEASE | — | F-001/F-026/F-031/F-034 remain public-release blockers | Resume before any public release; keep credentials and research artifacts out of friend packages |
|
||
| R5 | DEFERRED BY USER | — | F-002/F-003/F-006/F-007/F-011/F-020/F-027/F-029/F-032 | Resume later with the bounded documentation-authority goal |
|
||
| R6 | NOT STARTED | — | F-004/F-005/F-012/F-016/F-023/F-028 | Wait for R3/R5 |
|
||
| R7 | NOT STARTED | — | F-017/F-018/F-024/F-025 | Wait for R3 |
|
||
| R8 | NOT STARTED | — | F-008/F-013/F-033 | Wait for R1–R3 and cleanup decisions |
|
||
| R9 | NOT STARTED | — | F-034 plus R4 provenance decisions | Wait for R4 |
|
||
| R10 | NOT STARTED | — | All blocking findings | Wait for blocking slices |
|
||
|
||
### R1 implementation checkpoint — 2026-08-18
|
||
|
||
**Working-tree base:** `15539a22a67f8d915d88f8b1d8126cd55eedda6e`
|
||
**Commit:** `0a934cf5` on `codex/release-stabilization`; the checkpoint is
|
||
durable on that campaign branch but is not yet merged to `main`.
|
||
|
||
Implementation:
|
||
|
||
- `LauncherProcessSupervisor.Dispose` now transfers `_process` ownership to a
|
||
local and clears the field under `_gate`, then performs stop, event removal,
|
||
and child disposal outside the gate.
|
||
- Public `Stop` and disposal share one `StopProcess` implementation, preserving
|
||
graceful-stop, close-window, timeout, kill, and post-kill observation order.
|
||
- `OnProcessExited` reads the event sender's optional exit code without holding
|
||
`_gate`, then commits the terminal transition through the existing ordered
|
||
state publisher. A callback already captured during teardown may therefore
|
||
finish instead of forming the supervisor/Process lock cycle.
|
||
- `DisposeAllowsAnAlreadyCapturedExitCallbackToComplete` uses explicit barriers:
|
||
the fake captures the exit delegate before unsubscription; its disposal
|
||
releases the callback and waits for it to return. There are no timing sleeps
|
||
in the oracle, and an emergency release keeps failure against the old code
|
||
bounded rather than wedging the test host.
|
||
|
||
Sabotage and focused evidence:
|
||
|
||
- With the old lock shape temporarily restored and the new test retained, the
|
||
test failed with its expected five-second timeout. The fake's cleanup barrier
|
||
then released the old cycle, so the test process exited normally.
|
||
- With the fix restored, the same test passed in 21 ms.
|
||
- The race test passed 25/25 times in fresh `dotnet test` processes.
|
||
- All `LauncherProcessSupervisorTests` passed: 22/22.
|
||
- Complete Launcher.Core passed under a 180-second hard process bound:
|
||
339 passed / 0 skipped / 0 failed in 52 seconds.
|
||
|
||
Complete-solution evidence:
|
||
|
||
- Release build completed inside a 300-second bound with 0 warnings / 0 errors
|
||
in the evaluated incremental build.
|
||
- The exact serialized command was
|
||
`dotnet test AcDream.slnx -c Release --no-build --no-restore --nologo -m:1`,
|
||
launched in a fresh child process for each run. An outer process watchdog
|
||
allowed 900 seconds, killed the complete process tree on expiry, and treated
|
||
timeout as failure.
|
||
- Run 1: 12 assemblies, 14,748 passed / 77 skipped / 0 failed, 1:28.822,
|
||
bounded exit code 0.
|
||
- Run 2: 12 assemblies, 14,748 passed / 77 skipped / 0 failed, 1:30.241,
|
||
bounded exit code 0.
|
||
|
||
Adjacent evidence, deliberately not folded into R1:
|
||
|
||
- One default-parallel whole-solution run terminated normally in 58.148
|
||
seconds—important negative evidence for the former hang—but failed one
|
||
`AcDream.Launcher.Tests` Avalonia headless cleanup because a compositor was
|
||
accessed from a non-owning thread. The Launcher test project then passed
|
||
67/67 alone. R1 makes no Avalonia changes; R2/R3 must decide the supported CI
|
||
scheduling and ownership of that pre-existing parallel-run failure.
|
||
- The known duplicate Core theory row and 77 skip classifications remain
|
||
unchanged and belong to R3. R1 does not use their headline count as proof of
|
||
test quality.
|
||
|
||
Changed implementation/test files:
|
||
|
||
- `src/AcDream.Launcher.Core/Launching/LauncherProcessSupervisor.cs`
|
||
- `tests/AcDream.Launcher.Core.Tests/Launching/LauncherProcessSupervisorTests.cs`
|
||
|
||
Rollback is `git revert 0a934cf5`; do not rewrite branch history.
|
||
|
||
### R2 complete-gate checkpoint — 2026-08-18
|
||
|
||
**Working-tree base:** `0a934cf5781c003375c14af9a1f565254df0f9f9`
|
||
**Commit:** `2ac05486` on `codex/release-stabilization`; the checkpoint is
|
||
durable on that campaign branch but is not yet merged to `main`.
|
||
|
||
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.
|
||
|
||
Rollback is `git revert 2ac05486`; do not rewrite branch history.
|
||
|
||
### R2 reproducibility closeout — 2026-08-18
|
||
|
||
**Working-tree base:** `b459e0cf0cab9241b0771d2ce6838083f2c84162`
|
||
|
||
**Implementation commit:** `c38f6b88522750abc2e4acf1898ed566c5576e4a`
|
||
on `codex/release-stabilization`; the closeout is durable on that campaign
|
||
branch but is not yet merged to `main`.
|
||
|
||
Repository policy and dependency graph:
|
||
|
||
- `Directory.Build.props` is the common .NET 10, language, nullable, latest
|
||
analysis, warnings-as-errors, deterministic-build, and lock-file authority.
|
||
- `Directory.Packages.props` centrally pins all 30 direct package versions.
|
||
All 89 `PackageReference` sites are versionless; no project-local version can
|
||
silently drift.
|
||
- `NuGet.Config` clears machine fallback folders and package sources, then
|
||
declares only `nuget.org`.
|
||
- Every supported project owns `packages.neutral.lock.json` (44 files). Every
|
||
shippable source project additionally owns `packages.win-x64.lock.json` and
|
||
`packages.linux-x64.lock.json` (14 of each; 72 graphs total). Conventional
|
||
`packages.lock.json` files are intentionally absent because NuGet gives that
|
||
filename precedence over `NuGetLockFilePath`, preventing adjacent neutral
|
||
and RID graphs.
|
||
- `tools/update-package-locks.ps1` is the one intentional update path. The
|
||
release gate and the launcher's nested Bake publish use forced locked restore,
|
||
so stale `obj/` assets cannot hide a disagreement and a normal gate cannot
|
||
rewrite dependency resolution.
|
||
|
||
Complete maintained build surface:
|
||
|
||
- All 13 tracked .NET tools were repaired against package/owned interfaces,
|
||
documented in `tools/README.md`, and added to `AcDream.slnx`.
|
||
- The gate now verifies that every `.csproj` under `src/`, `tests/`, and
|
||
`tools/` is a solution member, requires the expected lock graphs, and records
|
||
their hashes in the evidence bundle. The supported graph is 44 projects.
|
||
- The older script/probe archive under F-004 is unchanged. Classifying that
|
||
historical material remains R6 work; the R2 change only makes the maintained
|
||
.NET tools truthful and reproducible.
|
||
|
||
Warning cleanup and test-gate stability:
|
||
|
||
- A clean complete recompilation originally exposed 26 warnings, all in test
|
||
and diagnostic code. Assertion-specific analyzers, nullable test doubles,
|
||
and nullable DAT probe boundaries were corrected without changing product
|
||
behavior.
|
||
- The one known redundant historical Core theory input remains for R3 behind a
|
||
site-scoped `xUnit1025` suppression. The central policy still makes any new
|
||
duplicate row a build failure.
|
||
- The launcher's seven editor-focus variants now execute in one Avalonia test
|
||
application session. This prevents the headless framework from attempting
|
||
compositor reinitialization on a non-owning thread. The suite passed 11
|
||
consecutive focused runs before the full gate. Aggregating seven theory rows
|
||
into one fact reduces the headline passed count by six; all seven variants
|
||
are still executed and asserted.
|
||
- The launcher package-boundary test now verifies versionless project
|
||
references against the central version table rather than incorrectly
|
||
requiring inline versions.
|
||
|
||
Reproducibility evidence:
|
||
|
||
- Forced locked re-evaluation of all 44 neutral and all 28 RID graphs changed
|
||
zero lock hashes.
|
||
- A locked restore into an empty global package cache, with `--no-cache`,
|
||
succeeded from the sole configured source. NuGet assets recorded no fallback
|
||
package folder.
|
||
- A forced nested launcher-to-Bake publish selected the appropriate RID graph,
|
||
emitted the Bake executable, and changed zero lock hashes.
|
||
- `pwsh ./tools/run-release-gate.ps1` ran on the clean exact commit
|
||
`c38f6b88522750abc2e4acf1898ed566c5576e4a`, SDK `10.0.300`, RID `win-x64`,
|
||
in 121.398 seconds. Restore was forced and locked; all 44 projects built with
|
||
0 warnings / 0 errors; all 12 test assemblies completed with 14,742 passed /
|
||
77 skipped / 0 failed. The gate recorded `WorktreeDirty: false`.
|
||
|
||
No product source behavior changed in this closeout. The known duplicate theory
|
||
row, classification of the 77 environment-dependent skips, test naming/value
|
||
review, and stale public headline counts remain explicitly assigned to R3 and
|
||
the later documentation-authority slice. R2 is complete on the campaign branch.
|
||
|
||
Rollback is `git revert c38f6b88`; do not rewrite branch history.
|
||
|
||
## 18. Session start protocol
|
||
|
||
Every implementation session begins by:
|
||
|
||
1. reading this plan, the executive audit, and the findings for the active
|
||
slice;
|
||
2. running `git status --short`, `git rev-parse HEAD`, and checking the ledger's
|
||
recorded commit against the working tree;
|
||
3. reading all files/tests named by the active finding before editing;
|
||
4. confirming there is no overlapping uncommitted user work;
|
||
5. restating the bounded slice outcome and gates in the session update;
|
||
6. working only the first non-blocked active slice unless the plan explicitly
|
||
allows parallel work.
|
||
|
||
## 19. Session handoff protocol
|
||
|
||
Before ending any session, record in §17 or a linked dated closeout:
|
||
|
||
- exact commit/worktree state and every file changed;
|
||
- decisions made and alternatives rejected;
|
||
- invariant/evidence destinations for anything removed;
|
||
- exact commands, pass/fail/skip counts, timeouts, and artifact paths;
|
||
- review findings and whether they were closed;
|
||
- remaining risks, blockers, and user/legal decisions;
|
||
- rollback command or precise reversal procedure;
|
||
- one exact next action that can be started without chat context.
|
||
|
||
A slice is not `DONE` because its code compiles or a focused test passes. It is
|
||
done only when its exit criteria, complete required gate, evidence update,
|
||
review, and cross-session ledger entry are all complete.
|
||
|
||
## 20. Immediate next action
|
||
|
||
Fast-forward `main` through the completed R1–R3 stabilization branch and push
|
||
the merged result. R4 and R5 are explicitly deferred for the friend-only
|
||
release. Before any public release, resume R4; when maintainability work
|
||
resumes, begin with the bounded R5 documentation-authority goal. Do not begin
|
||
bulk comment, artifact, giant-file, or unrelated cleanup first.
|