34 KiB
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
Findings: ../reviews/findings-ledger.md
Coverage proof: ../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
- Protect behavior before cleanup. Establish a deterministic complete gate before broad refactors, comment cleanup, or file decomposition.
- 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.
- One current truth. Stable architecture and release state must not depend on choosing between README, roadmap, milestone, campaign, memory, or tool-specific instruction copies.
- Separate evidence from contracts. Source comments explain the current invariant. Dated research records preserve investigation history. Raw captures live in an explicit artifact tier.
- 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.
- Bound every external interaction. Process waits, network operations, test runs, and release steps require timeouts, cancellation, and diagnostic artifacts on failure.
- Small reversible slices. Each slice gets focused tests, a complete gate, a reviewable commit, a rollback description, and a plan-ledger update.
- 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
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:
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.Sleepas 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
- Hermetic release lane: default CI; unavailable local data is never a silent passing return.
- Installed-DAT/prepared-package lane: explicit prerequisites and per-suite skip identity; result published separately.
- Live/connected/visual/listening lane: operator-owned, dated evidence; never counted as ordinary unit coverage.
- 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.mdstable 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.mdproduct 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.Abstractionsif 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
RuntimeSetPositionStateTransitionTypesRetailUiRuntimeLiveEntityRuntimeWorldSessionWbDrawDispatcher
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.Disposenow transfers_processownership to a local and clears the field under_gate, then performs stop, event removal, and child disposal outside the gate.- Public
Stopand disposal share oneStopProcessimplementation, preserving graceful-stop, close-window, timeout, kill, and post-kill observation order. OnProcessExitedreads 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.DisposeAllowsAnAlreadyCapturedExitCallbackToCompleteuses 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 testprocesses. - All
LauncherProcessSupervisorTestspassed: 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.TestsAvalonia 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.cstests/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.jsonpins the accepted .NET 10 SDK feature band at10.0.300withlatestPatchroll-forward and prerelease SDKs disabled. Every existingactions/setup-dotnetstep now reads that file instead of floating on10.0.x.tools/run-release-gate.ps1discovers every project undertests/that declaresMicrosoft.NET.Test.SdkorIsTestProject, verifies the project is present inAcDream.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, andSHA256SUMS.txt. .github/workflows/release-gate.ymlruns the gate on pull requests, pushes tomain, and manual dispatch onwindows-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.mdis the repository-owned local/CI runbook.
Test-isolation corrections, with no product behavior change:
- Four
MainWindowViewTeststhat callShow()now close their window and pump dispatcher cleanup infinallyon 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 anIOExceptionand the deliberately no-throw capture sink latched off. The helper now reads withFileShare.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.ps1completed in 107.337 seconds on SDK10.0.300, RIDwin-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.propsis the common .NET 10, language, nullable, latest analysis, warnings-as-errors, deterministic-build, and lock-file authority.Directory.Packages.propscentrally pins all 30 direct package versions. All 89PackageReferencesites are versionless; no project-local version can silently drift.NuGet.Configclears machine fallback folders and package sources, then declares onlynuget.org.- Every supported project owns
packages.neutral.lock.json(44 files). Every shippable source project additionally ownspackages.win-x64.lock.jsonandpackages.linux-x64.lock.json(14 of each; 72 graphs total). Conventionalpackages.lock.jsonfiles are intentionally absent because NuGet gives that filename precedence overNuGetLockFilePath, preventing adjacent neutral and RID graphs. tools/update-package-locks.ps1is the one intentional update path. The release gate and the launcher's nested Bake publish use forced locked restore, so staleobj/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 toAcDream.slnx. - The gate now verifies that every
.csprojundersrc/,tests/, andtools/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
xUnit1025suppression. 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.ps1ran on the clean exact commitc38f6b88522750abc2e4acf1898ed566c5576e4a, SDK10.0.300, RIDwin-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 recordedWorktreeDirty: 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:
- reading this plan, the executive audit, and the findings for the active slice;
- running
git status --short,git rev-parse HEAD, and checking the ledger's recorded commit against the working tree; - reading all files/tests named by the active finding before editing;
- confirming there is no overlapping uncommitted user work;
- restating the bounded slice outcome and gates in the session update;
- 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.