SHOULD-FIX 1: RetailClientCommandCatalog's ~45 catalog leaf verbs were showing acdream-authored Summary text for /help <verb> instead of retail's own Detail_HelpType(2) text. Byte-swept every Help* handler against the PDB-paired acclient.exe (verified MATCH), confirmed each Detail/Summary branch by reading the actual decompiled if/else shape (address order and string length both proved unreliable alone), and fixed a sweep_weenie_strings.py 800-char truncation bug that silently dropped several longer Detail branches. Resolved every ambiguous CmdHashData-registered verb (hor/hr/hom/hoa/alh/ah/friends_add/ friends_remove/squelch/unsquelch) by reading for Binary Ninja's nullptr-4th-arg decompiler artifact instead of trusting it. Coverage: 42 of 47 distinct catalog Definitions verbatim-extracted, 4 confirmed-null (index/clist/on/off register with a genuinely null help pointer — DoHelp falls to UnknownCommand for these, now reproduced), 1 honest UNVERIFIED (messagetypes builds its text from a runtime enum table, not a static string). ChatCommandRouter now prefers retail Detail text over the catalog summary; RetailCommandHelpTable's class doc no longer overclaims its own scope. SHOULD-FIX 2: extracted the a5a7eb4f-class OnInterfaceText wiring into a testable CreateChatViewModel method and added ComposedChatViewModelWiresOnInterfaceTextToSpewBox, which the prior FakeFactory-based test suite could never exercise. SHOULD-FIX 3: retires register row AP-113. DoLifestone/DoMarketplace print their own 0x1A refusal text (byte-recovered, UTF-16LE) instead of falling through to the generic 0x26 fallback; ChatCommandRouter's comment corrected to state the fallback's real scope. SHOULD-FIX 4: corrected the divergence register's stale AP section header sentence about AP-190's opacity default (refuted bycc582899). NITs: (a) HeadlessStaticStateAudit routes through the injected HeadlessDiagnosticWriter instead of Console.WriteLine; (b) a bounded 300-pump liveness diagnostic on the IsQuiescent conductor gate (no retry, no behavior change); (c) fixed the #365 hydration test's doc comment contradiction against diagnosis §8; (d) the 0x26 fallback dispatches on WeenieErrorMessages' own Type instead of hardcoding ClientLocal. Full Release suite: 12,553 passed / 4 skipped / 0 failed (baseline03404b71: 12,542/4/0; net +11 tests, zero regressions). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
79 lines
3.4 KiB
C#
79 lines
3.4 KiB
C#
using System.Reflection;
|
|
using AcDream.Core.Physics;
|
|
using AcDream.Headless.Configuration;
|
|
using AcDream.Headless.Diagnostics;
|
|
|
|
namespace AcDream.Headless.Hosting;
|
|
|
|
/// <summary>
|
|
/// Rejects process-global physics probes whose mutable capture cursors and
|
|
/// last-hit fields cannot be attributed safely when several Runtime roots
|
|
/// share one process. Ordinary diagnostics remain session-labelled through
|
|
/// <see cref="Diagnostics.HeadlessDiagnosticWriter"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// #365 Step 1: the refusal's rationale is multi-root attribution ambiguity
|
|
/// — it does not hold for a process that owns exactly ONE session, since
|
|
/// there is no second root to confuse a probe's cursor/last-hit fields
|
|
/// with. Refusing anyway made the exact probe built to diagnose the #365
|
|
/// hydration stall (<c>ACDREAM_PROBE_PARK=1</c>) impossible to run against
|
|
/// the single-session repro that needed it. A <paramref name="sessionCount"/>
|
|
/// of 1 now logs the enabled probes loudly and proceeds; anything else
|
|
/// keeps the original hard refusal, naming every enabled probe.
|
|
/// </remarks>
|
|
internal static class HeadlessStaticStateAudit
|
|
{
|
|
/// <summary>
|
|
/// Consolidated-review round (2026-08-10), NIT (a): <paramref name="diagnostics"/>
|
|
/// is the SAME structured writer every other headless diagnostic uses
|
|
/// (<see cref="HeadlessProcessHost"/>'s <c>_diagnostics</c> field, now
|
|
/// constructed before this call rather than after it) — the raw
|
|
/// <c>Console.WriteLine</c> this replaced bypassed the session-labelled
|
|
/// JSON stream every other producer writes into.
|
|
/// </summary>
|
|
internal static void ValidateProcessIsolation(
|
|
int sessionCount, HeadlessDiagnosticWriter diagnostics)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(diagnostics);
|
|
var enabled = new List<string>();
|
|
foreach (PropertyInfo property in typeof(PhysicsDiagnostics)
|
|
.GetProperties(BindingFlags.Public | BindingFlags.Static)
|
|
.OrderBy(static property => property.Name, StringComparer.Ordinal))
|
|
{
|
|
if (property.PropertyType != typeof(bool)
|
|
|| property.GetMethod is null
|
|
|| (!property.Name.StartsWith(
|
|
"Probe",
|
|
StringComparison.Ordinal)
|
|
&& !property.Name.StartsWith(
|
|
"Dump",
|
|
StringComparison.Ordinal)))
|
|
{
|
|
continue;
|
|
}
|
|
if (property.GetValue(null) is true)
|
|
enabled.Add(property.Name);
|
|
}
|
|
if (PhysicsDiagnostics.CollisionShadowSampleEvery > 0)
|
|
enabled.Add(nameof(PhysicsDiagnostics.CollisionShadowSampleEvery));
|
|
if (PhysicsResolveCapture.IsEnabled)
|
|
enabled.Add(nameof(PhysicsResolveCapture));
|
|
|
|
if (enabled.Count == 0)
|
|
return;
|
|
|
|
if (sessionCount == 1)
|
|
{
|
|
diagnostics.Message(
|
|
sessionId: "process",
|
|
eventName: FormattableString.Invariant(
|
|
$"headless-audit: single-session process — process-global physics probes enabled: {string.Join(", ", enabled)}"));
|
|
return;
|
|
}
|
|
|
|
throw new HeadlessConfigurationException(
|
|
"Multi-session headless mode cannot use process-global "
|
|
+ "physics probes. Disable: "
|
|
+ string.Join(", ", enabled));
|
|
}
|
|
}
|