wip: Campaign LA LA1 fix round — INCOMPLETE, stopped mid-task

Agent was stopped for token budget partway through the LA1 review fix
round. Landed here: F1 best-effort SessionStatusWriter, F2 App reader
tolerance (paths/mode), F5 argument-parsing hardening, plus new tests.
NOT DONE: F4 shared-fixture production shape (was the next step), F3
reconnect disconnected edge + recorded limitation, F6 exited
idempotency/reasons, F7 structural redaction test, F8 platform-guard
test + comment fix, optional RuntimeOptions PrintMembers redaction.

Build/test state UNVERIFIED at this commit. Next session: finish the
remaining findings, run the suites, then narrow re-review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-14 16:32:52 +02:00
parent c9fc7f4a66
commit 75a6724d5b
9 changed files with 628 additions and 52 deletions

View file

@ -42,6 +42,26 @@ internal sealed class SessionConfiguration
internal sealed class SessionProcessSettings
{
public SessionContentDescriptor? Content { get; init; }
/// <summary>Campaign LA slice LA1 review fix (F2): accepted so the SAME
/// document also satisfies the Headless loader's own
/// <c>process.paths</c> member (<c>HeadlessPathOverrides</c>) — parsed
/// and ignored here, exactly like <see cref="SessionDescriptor.Policy"/>
/// and <see cref="SessionDescriptor.CharacterOptions"/> below. App has
/// no config/data/cache directory override concept of its own (those
/// come from <c>ApplicationPathSet</c>/env vars on this host); only the
/// Headless host consumes overrides composed under this key.</summary>
public SessionProcessPathOverrides? Paths { get; init; }
}
/// <summary>Accepted-but-ignored mirror of Headless's
/// <c>HeadlessPathOverrides</c> shape — see
/// <see cref="SessionProcessSettings.Paths"/>.</summary>
internal sealed class SessionProcessPathOverrides
{
public string? ConfigDirectory { get; init; }
public string? DataDirectory { get; init; }
public string? CacheDirectory { get; init; }
}
internal sealed class SessionContentDescriptor
@ -75,6 +95,19 @@ internal sealed record SessionDescriptor
/// App has no bot-policy concept.</summary>
public SessionPolicyDescriptor? Policy { get; init; }
/// <summary>Campaign LA slice LA1 review fix (F2): pinned-contract
/// mode discriminator. ABSENT means today's ONLY App behavior — an
/// ordinary play session — so every document written before this field
/// existed keeps parsing unchanged. <c>"probe"</c> (LA2's connect
/// ▸ characterList ▸ graceful-disconnect flow, no EnterWorld) is
/// HEADLESS-ONLY; the App loader rejects it with an explicit message
/// naming the field rather than the caller ever seeing a raw unmapped-
/// member <see cref="System.Text.Json.JsonException"/>. Any other value
/// is a configuration error — the pinned contract defines no other
/// mode literal, so a document is either silent about mode (play) or
/// says "probe" exactly.</summary>
public string? Mode { get; init; }
[JsonRequired]
public SessionCredentialDescriptor Credential { get; init; } = new();