acdream/docs/plans/2026-08-18-release-stabilization.md

34 KiB
Raw Blame History

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

  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

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 R1R3.

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 R2R3 yes
R6 Dead presentation/backend/probe surfaces removed; supported tools reproducible R3R5 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, R6R7 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 R1R3 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.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 R1R3. 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; tracking/owner assignment pending Audit complete at 15539a22; user started R1 Track plan+audit artifacts; assign R4 owner
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 ON CAMPAIGN BRANCH; not yet merged 2ac05486, c38f6b88 Checkpoints below; F-014/F-019 resolved, F-010 machine-readable, supported .NET tool portion of F-004 resolved Begin R3; merge through normal review
R3 NOT STARTED T-002T-018; F-015/F-021/F-022/F-030 Begin complete test inventory, naming, skip, and value classification
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 R2R3
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 R1R3 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

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.