docs(headless-console): record implementation ledger and connected proof
Appends the plan's ledger with what shipped, the deliberate deviation from the plan's illustrative bracket-prose example (Headless cannot reference AcDream.UI.Abstractions, so the console's chat rendering is its own terminal-shaped format using the same channel-name strings, not a byte-for-byte port of ChatVM.FormatEntry), the chosen console default and why, and the exact connected proof recipe for the owner to run against a live ACE with +Acdream and MossTank (not run here per the contract). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
4d5da2dcd5
commit
97b1c9f6ce
1 changed files with 103 additions and 0 deletions
|
|
@ -66,3 +66,106 @@ it or the lead may, it is not a visual gate.
|
|||
|
||||
## Ledger
|
||||
- 2026-09-07 planned; implementer dispatched.
|
||||
- 2026-09-07 IMPLEMENTED. The dispatch seam already existed:
|
||||
`AcDream.Runtime.Chat.ChatCommandRouter.Submit` is the SAME presentation-
|
||||
free pipeline `LoginCommandSequence` (headless) and every graphical chat
|
||||
window (`ChatWindowController`, `FloatingChatWindowController`,
|
||||
`RetailUiRuntime`) already call — no lift was needed. Added
|
||||
`HeadlessSessionHost.SubmitConsoleLine` (`Hosting/HeadlessSessionHost.cs`)
|
||||
as the one new call site, reusing the host's own retained
|
||||
`LiveChatCommandSurface`/plugin registry (now promoted from ctor locals to
|
||||
fields) instead of a second parser.
|
||||
New files: `Configuration/HeadlessConsoleOptions.cs` (typed `--console` /
|
||||
`ACDREAM_HEADLESS_CONSOLE=1` / terminal-default resolution),
|
||||
`Hosting/HeadlessConsoleInputReader.cs` (background stdin thread → FIFO
|
||||
queue, never executes handler code), `Hosting/HeadlessConsoleController.cs`
|
||||
(drains the queue on the session tick via a new `HeadlessSessionHost.
|
||||
ConsolePump` hook; owns `/quit`/`/status`), `Hosting/
|
||||
HeadlessConsoleChatFormatter.cs` + `Hosting/HeadlessConsoleRenderer.cs`
|
||||
(renders the K2 bot event stream — `IRuntimeEventObserver`, the same
|
||||
interface a bot policy subscribes — as bracket-labelled lines:
|
||||
`[Tell] Bob: hi`, `[Fellowship] …`, `[Local] …`), `Hosting/
|
||||
HeadlessConsoleChatFeedback.cs` (decorates `RuntimeChatCommandFeedback` so
|
||||
retail's transient SpewBox/`ClientLocal` interface text — which never
|
||||
touches `ChatLog`, so it never reaches the K2 event stream — also reaches
|
||||
the console). `/quit` cancels a `CancellationTokenSource` linked into the
|
||||
scheduler's run token in `HeadlessProcessHost` (the SAME graceful-exit
|
||||
path an external Ctrl+C/SIGTERM already takes); `/status` reports
|
||||
generation, position (or "unknown" without a live movement controller),
|
||||
and loaded-plugin count (no plugin today reports a richer macro-state
|
||||
string). Console only attaches for a single-session `run` (per the plan's
|
||||
"out of scope for the first cut" multi-session note); constructed AFTER
|
||||
every session's own credential resolution so the reader thread never
|
||||
races a `StandardInput`-provider password prompt on the same stream.
|
||||
Chosen console default: on when `!Console.IsInputRedirected` (a real
|
||||
operator at a terminal), off when redirected (scripts/CI/piped fixtures,
|
||||
where a blocked `ReadLine` on a background thread would just sit idle) —
|
||||
resolved once in `Program.cs`, the only place that can see the real
|
||||
`Console`.
|
||||
Deviation from the plan's illustrative example: retail's own transcript
|
||||
never prefixes Tell/Local lines with a bracket (`ChatVM.FormatEntry`
|
||||
renders "Bob tells you, ..."/"Bob says, ..." with no label) — Headless
|
||||
cannot reference `AcDream.UI.Abstractions` (the dependency-boundary
|
||||
test), so `HeadlessConsoleChatFormatter` is a deliberately DIFFERENT,
|
||||
terminal-shaped "[Label] Sender: text" rendering using the SAME channel-
|
||||
name strings (matching the plan's literal `[Tell] Bob: hi` example), not
|
||||
a byte-for-byte port of the graphical prose.
|
||||
Tests: `tests/AcDream.Headless.Tests/HeadlessConsoleTests.cs` (20 new
|
||||
tests — options resolution, command-line flag parsing, reader-thread
|
||||
ordering/never-on-reader-thread, controller drain/quit/status, chat
|
||||
formatting, and full `/say`/plain-text/plugin-verb/unknown-verb dispatch
|
||||
against a real `HeadlessSessionHost` + `FixtureSessionOperations`, no live
|
||||
server) plus the existing `LaunchOptionsDocumentationTests` (4/4 green)
|
||||
and `HeadlessDependencyBoundaryTests` (3/3 green, unchanged — Headless
|
||||
still references only `AcDream.Runtime`). Every test in this batch was
|
||||
mutation-checked to fail before the corresponding production line existed
|
||||
(see the implementer's final report for the specific mutations run:
|
||||
skipping the interface-text callback, skipping `_quitRequested.Cancel()`,
|
||||
forcing `TryHandlePluginCommand` to always return false, dropping the
|
||||
reader thread's `Enqueue`, and swapping `ChatChannelKind.Say` for `.Tell`
|
||||
in `SubmitConsoleLine`).
|
||||
Suites: `dotnet test tests/AcDream.Headless.Tests -c Release` → 193
|
||||
passed / 1 pre-existing failure (`LinuxRejectsGroupOrOtherCredentialPermissions`,
|
||||
a Linux-only lane test that cannot run on this Windows host — unrelated
|
||||
to this change) / 194 total. `dotnet test tests/AcDream.Runtime.Tests -c
|
||||
Release` → 1891/1891 passed. `dotnet test tests/AcDream.App.Tests -c
|
||||
Release --filter "FullyQualifiedName~Chat|FullyQualifiedName~Command|
|
||||
FullyQualifiedName~LaunchOptions"` → 414 passed / 2 pre-existing failures
|
||||
(`ChatIndicatorButtonLiveMountProbeTests`/`OptionsPanelLiveMountProbeTests`
|
||||
— both gated on `ACDREAM_PROBE_LIVE_MOUNT=1`, a manual live-DAT probe lane,
|
||||
unrelated to this change) / 3 skipped / 419 total. `dotnet build
|
||||
AcDream.slnx -c Release` green throughout.
|
||||
|
||||
### Connected proof recipe (owner runs; NOT run by the implementer)
|
||||
|
||||
Against a running local ACE at `127.0.0.1:9000` with MossTank loaded for
|
||||
the second half:
|
||||
|
||||
```powershell
|
||||
$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call"
|
||||
dotnet run --project src\AcDream.Headless\AcDream.Headless.csproj --no-build -c Release -- `
|
||||
run --config <path-to-a-one-session-config.json> `
|
||||
-user testaccount -password testpassword --console
|
||||
```
|
||||
|
||||
The referenced config's one session should target character `+Acdream`
|
||||
(server guid `0x5000000A`) against `127.0.0.1:9000`, an `idle` bot policy,
|
||||
and (for the second half) the MossTank plugin id under `plugins`. Once the
|
||||
console prints `entered world`:
|
||||
|
||||
1. Type `/say hello` and press Enter — expect the SAME line ACE echoes back
|
||||
to any other observer (a retail client or a second acdream session
|
||||
watching `+Acdream`) to also print `[Local] You: hello` in this console
|
||||
(the server's own HearSpeech echo, rendered through the normal chat
|
||||
event stream).
|
||||
2. Type `/status` — expect a line with `generation=`, `position=` (a real
|
||||
cell/local-frame triple once in world), and `plugins=N loaded`.
|
||||
3. With MossTank loaded, type `/vt start` (or whatever verb MossTank
|
||||
registers) — expect MossTank's own handler to run (check its own
|
||||
status/log output) and confirm NOTHING was sent to the wire for that
|
||||
line (no `@vt` server command).
|
||||
4. Type `/quit` — expect a graceful ACE logout (same as the existing
|
||||
Ctrl+C behavior) and the process to exit 0.
|
||||
|
||||
This is not a visual gate; the owner (or the lead) runs it opportunistically
|
||||
before considering the plan CLOSED.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue