fix(platform): Campaign LA LA0 review fixes — CI Linux lanes, arch doc, self-guard

Opus dual-lens review of cb6502c8 passed with six findings; this lands
the fix round:
1. headless-portability.yml: AcDream.Platform src/tests join both path
   triggers and the presentation-free build/test arrays — the moved XDG
   tests run on ubuntu-latest again (they had fallen out of every Linux
   lane).
2. acdream-architecture.md: AcDream.Platform gets its own layer block;
   Runtime may-reference clause updated (the guard changed in cb6502c8,
   its human-readable twin had not).
3. PlatformDependencyBoundaryTests: the BCL-only contract (zero
   project/package references) is now enforced, not just observed.
4. memory/project_linux_graphical.md canonical seam renamed.
5. Plan LA0 recon corrected: the K0 Headless guard was never the guard
   needing amendment (it asserts Headless own refs); Runtime own-refs
   guard was — the commit did the right thing, the plan text now says so.
6. App declares its AcDream.Platform reference explicitly per its own
   convention instead of riding transitivity.

Platform.Tests: 4 passed (3 moved + the new guard).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-14 15:30:04 +02:00
parent cb6502c8a5
commit a49e92df3a
6 changed files with 101 additions and 16 deletions

View file

@ -5,6 +5,7 @@ on:
paths: paths:
- ".github/workflows/headless-portability.yml" - ".github/workflows/headless-portability.yml"
- "AcDream.slnx" - "AcDream.slnx"
- "src/AcDream.Platform/**"
- "src/AcDream.Core/**" - "src/AcDream.Core/**"
- "src/AcDream.Core.Net/**" - "src/AcDream.Core.Net/**"
- "src/AcDream.Content/**" - "src/AcDream.Content/**"
@ -13,6 +14,7 @@ on:
- "src/AcDream.Headless/**" - "src/AcDream.Headless/**"
- "src/AcDream.App/**" - "src/AcDream.App/**"
- "src/AcDream.UI.Abstractions/**" - "src/AcDream.UI.Abstractions/**"
- "tests/AcDream.Platform.Tests/**"
- "tests/AcDream.Core.Tests/**" - "tests/AcDream.Core.Tests/**"
- "tests/AcDream.Core.Net.Tests/**" - "tests/AcDream.Core.Net.Tests/**"
- "tests/AcDream.Content.Tests/**" - "tests/AcDream.Content.Tests/**"
@ -26,6 +28,7 @@ on:
paths: paths:
- ".github/workflows/headless-portability.yml" - ".github/workflows/headless-portability.yml"
- "AcDream.slnx" - "AcDream.slnx"
- "src/AcDream.Platform/**"
- "src/AcDream.Core/**" - "src/AcDream.Core/**"
- "src/AcDream.Core.Net/**" - "src/AcDream.Core.Net/**"
- "src/AcDream.Content/**" - "src/AcDream.Content/**"
@ -34,6 +37,7 @@ on:
- "src/AcDream.Headless/**" - "src/AcDream.Headless/**"
- "src/AcDream.App/**" - "src/AcDream.App/**"
- "src/AcDream.UI.Abstractions/**" - "src/AcDream.UI.Abstractions/**"
- "tests/AcDream.Platform.Tests/**"
- "tests/AcDream.Core.Tests/**" - "tests/AcDream.Core.Tests/**"
- "tests/AcDream.Core.Net.Tests/**" - "tests/AcDream.Core.Net.Tests/**"
- "tests/AcDream.Content.Tests/**" - "tests/AcDream.Content.Tests/**"
@ -78,6 +82,7 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
$projects = @( $projects = @(
"src/AcDream.Platform/AcDream.Platform.csproj",
"src/AcDream.Plugin.Abstractions/AcDream.Plugin.Abstractions.csproj", "src/AcDream.Plugin.Abstractions/AcDream.Plugin.Abstractions.csproj",
"src/AcDream.Core/AcDream.Core.csproj", "src/AcDream.Core/AcDream.Core.csproj",
"src/AcDream.Core.Net/AcDream.Core.Net.csproj", "src/AcDream.Core.Net/AcDream.Core.Net.csproj",
@ -98,6 +103,7 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
$projects = @( $projects = @(
"tests/AcDream.Platform.Tests/AcDream.Platform.Tests.csproj",
"tests/AcDream.Core.Net.Tests/AcDream.Core.Net.Tests.csproj", "tests/AcDream.Core.Net.Tests/AcDream.Core.Net.Tests.csproj",
"tests/AcDream.Content.Tests/AcDream.Content.Tests.csproj", "tests/AcDream.Content.Tests/AcDream.Content.Tests.csproj",
"tests/AcDream.Runtime.Tests/AcDream.Runtime.Tests.csproj", "tests/AcDream.Runtime.Tests/AcDream.Runtime.Tests.csproj",

View file

@ -266,14 +266,21 @@ src/
World/ World/
RuntimeWorldEnvironmentState.cs -> canonical calendar/time/weather owner RuntimeWorldEnvironmentState.cs -> canonical calendar/time/weather owner
RuntimeWorldTransitState.cs -> canonical reveal generation/readiness owner RuntimeWorldTransitState.cs -> canonical reveal generation/readiness owner
Platform/
ApplicationPathSet.cs -> shared BCL-only XDG/Windows config, data,
cache, plugin, screenshot, and diagnostic paths
RuntimeGenerationReset.cs -> one retryable canonical-generation reset RuntimeGenerationReset.cs -> one retryable canonical-generation reset
-> Slice J complete; graphical and no-window hosts share one GameRuntime -> Slice J complete; graphical and no-window hosts share one GameRuntime
-> may reference Core, Core.Net, Content, and Plugin.Abstractions only -> may reference Core, Core.Net, Content, Plugin.Abstractions, and
Platform only
-> must never reference App, UI, Silk.NET, OpenAL, or Arch -> must never reference App, UI, Silk.NET, OpenAL, or Arch
AcDream.Platform/ BCL-only portable path contract (Campaign LA LA0)
ApplicationPathSet.cs -> shared XDG/Windows config, data, cache,
plugin, screenshot, and diagnostic paths
-> zero project/package references (guarded by
tests/AcDream.Platform.Tests/PlatformDependencyBoundaryTests.cs);
Runtime references it and re-exports transitively to App/Headless;
the external launcher (AcDream.Launcher.Core) references ONLY this
project from the game solution
AcDream.Headless/ Linux/Windows no-window production host AcDream.Headless/ Linux/Windows no-window production host
Program.cs -> CLI entry only Program.cs -> CLI entry only
Configuration/ -> strict versioned process/session config Configuration/ -> strict versioned process/session config

View file

@ -89,12 +89,16 @@ Recon facts (2026-08-14): blast radius is the definition, six source files
`App/Program.cs`, `GameWindow.cs:533`, `HeadlessPathSet.cs`, `App/Program.cs`, `GameWindow.cs:533`, `HeadlessPathSet.cs`,
`HeadlessPlatformEnvironment.cs`; two more files are doc-comment-only), two `HeadlessPlatformEnvironment.cs`; two more files are doc-comment-only), two
test files (`ApplicationPathSetTests.cs` moves to a new test files (`ApplicationPathSetTests.cs` moves to a new
`tests/AcDream.Platform.Tests/` or stays keyed to the new assembly; `tests/AcDream.Platform.Tests/`;
`GraphicalLegacyConfigurationMigratorTests.cs` fixtures), and ONE dependency `GraphicalLegacyConfigurationMigratorTests.cs` fixtures), and the dependency
guard: `tests/AcDream.Headless.Tests/HeadlessDependencyBoundaryTests.cs` guards — CORRECTED post-review (the original recon here asserted the wrong
`HeadlessAssemblyReferencesOnlyTheRuntimeProject` asserts Headless references guard, the C4-closeout failure mode): the K0 Headless guard
exactly `[AcDream.Runtime.csproj]` — amend to the exact new set in the same (`HeadlessAssemblyReferencesOnlyTheRuntimeProject`) asserts HEADLESS's own
commit (deliberate, never silent). Namespace stays `AcDream.Runtime.Platform`? csproj reference list, which this move does not touch — it stays UNCHANGED;
the guard that actually needs amending is Runtime's own
`RuntimeDependencyBoundaryTests.RuntimeProjectDeclaresOnlyApprovedProjectDependencies`
(Runtime gains the `AcDream.Platform` reference), amended with a cited
comment in the same commit. Namespace stays `AcDream.Runtime.Platform`?
NO — rename to `AcDream.Platform` and fix the eight usings (clean naming beats NO — rename to `AcDream.Platform` and fix the eight usings (clean naming beats
avoiding a mechanical edit). Register new projects in `AcDream.slnx`. avoiding a mechanical edit). Register new projects in `AcDream.slnx`.
@ -400,10 +404,10 @@ LA6 adds CH-regression scrutiny; LA0 adds guard-integrity scrutiny.
| Slice | Status | Commits | Review | Notes | | Slice | Status | Commits | Review | Notes |
|---|---|---|---|---| |---|---|---|---|---|
| LA0 | — | | | | | LA0 | review PASS; fix round applied | `cb6502c8` + fixes | Opus PASS w/ 6 findings 2026-08-14; narrow re-review pending | Byte-identity proven; CI Linux lanes + arch doc + Platform self-guard + App explicit ref fixed; plan recon corrected |
| LA1 | — | | | | | LA1 | in flight (Sonnet) | | | pinned contract v1 + 5 optional fields |
| LA2 | — | | | | | LA2 | — | | | |
| LA3 | — | | | | | LA3 | in flight (Sonnet, isolated worktree) | | | pinned contract shared with LA1 |
| LA4 | — | | | | | LA4 | — | | | |
| LA5 | — | | | | | LA5 | — | | | |
| LA6 | — | | | | | LA6 | — | | | |

View file

@ -12,9 +12,10 @@ Linux gameplay or renderer fork.
Canonical seams: Canonical seams:
- `AcDream.Runtime.Platform.ApplicationPathSet` owns XDG/Windows config, data, - `AcDream.Platform.ApplicationPathSet` (moved out of Runtime by Campaign LA
cache, plugin, screenshot, and diagnostic paths for graphical and headless LA0, 2026-08-14) owns XDG/Windows config, data, cache, plugin, screenshot,
hosts. and diagnostic paths for graphical and headless hosts — and now for the
external launcher, which references only `AcDream.Platform`.
- `AcDream.App.Platform.GraphicalHostPlatformServices` owns one startup OS, - `AcDream.App.Platform.GraphicalHostPlatformServices` owns one startup OS,
architecture, RID, native-dependency manifest, path set, and pacing factory. architecture, RID, native-dependency manifest, path set, and pacing factory.
- `PlatformFramePacingWaiterFactory` selects the existing Windows - `PlatformFramePacingWaiterFactory` selects the existing Windows

View file

@ -58,6 +58,11 @@
<ProjectReference Include="..\AcDream.Core\AcDream.Core.csproj" /> <ProjectReference Include="..\AcDream.Core\AcDream.Core.csproj" />
<ProjectReference Include="..\AcDream.Core.Net\AcDream.Core.Net.csproj" /> <ProjectReference Include="..\AcDream.Core.Net\AcDream.Core.Net.csproj" />
<ProjectReference Include="..\AcDream.Content\AcDream.Content.csproj" /> <ProjectReference Include="..\AcDream.Content\AcDream.Content.csproj" />
<!-- Campaign LA LA0 review finding 6: App consumes AcDream.Platform
types directly (GraphicalHostPlatformServices, Program, GameWindow),
so the reference is declared explicitly per this file's convention
rather than ridden transitively through Runtime. -->
<ProjectReference Include="..\AcDream.Platform\AcDream.Platform.csproj" />
<ProjectReference Include="..\AcDream.UI.Abstractions\AcDream.UI.Abstractions.csproj" /> <ProjectReference Include="..\AcDream.UI.Abstractions\AcDream.UI.Abstractions.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -0,0 +1,62 @@
using System.Runtime.CompilerServices;
using System.Xml.Linq;
namespace AcDream.Platform.Tests;
// Campaign LA LA0 review finding 3: AcDream.Platform's entire premise is
// being the BCL-only assembly the external launcher can reference without
// pulling any gameplay code. That contract is what this guard enforces —
// the csproj must declare zero ProjectReference and zero PackageReference
// entries, forever, in the same spirit as Runtime's and Headless's
// dependency-boundary guards.
public sealed class PlatformDependencyBoundaryTests
{
[Fact]
public void PlatformProjectDeclaresNoProjectOrPackageDependencies()
{
var repositoryRoot = FindRepositoryRoot();
var projectPath = Path.Combine(
repositoryRoot,
"src",
"AcDream.Platform",
"AcDream.Platform.csproj");
var project = XDocument.Load(projectPath);
Assert.Empty(project.Descendants("ProjectReference"));
Assert.Empty(project.Descendants("PackageReference"));
}
private static string FindRepositoryRoot(
[CallerFilePath] string sourcePath = "")
{
string[] starts =
{
Path.GetDirectoryName(sourcePath) ?? string.Empty,
Directory.GetCurrentDirectory(),
AppContext.BaseDirectory,
};
foreach (string start in starts)
{
if (string.IsNullOrEmpty(start))
{
continue;
}
var directory = new DirectoryInfo(start);
while (directory is not null)
{
if (File.Exists(Path.Combine(
directory.FullName,
"AcDream.slnx")))
{
return directory.FullName;
}
directory = directory.Parent;
}
}
throw new DirectoryNotFoundException(
"Could not find AcDream.slnx above the source, working, or output directory.");
}
}