EveryInteractiveControlDeclaresARealHandlerBinding asserted an exact
Assert.Equal(156, controls.Length), backed by ~60 lines of running
commentary recording every markup edit that ever bumped the number. That
count was a pure change detector: it carried no signal the test's own
per-control handler/enabled loop couldn't already catch on its own, and
it forced an edit to THIS test file every time an unrelated tab gained
or lost a single control.
Replaced the exact count with Assert.NotEmpty(controls) — it still
guards the selector itself (a broken interactive-element-name filter
that matched nothing would otherwise pass the loop vacuously) — and kept
the real assertion (the per-control handler/enabled loop) unchanged.
Moved the removed count's full history into this same commit's ledger
entry in docs/plans/2026-09-07-campaign-vt-slice7-tabs.md, per item
F13's own instruction.
Mutation named: temporarily broke the controls selector (appended
`&& false` to the interactive-element filter) and confirmed
Assert.NotEmpty fails ("Collection was empty") before restoring it.
MossTank suite holds at 678 (no test added or removed, one assertion
replaced). Full solution build green; App markup/plugin filter 203/203.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Recaptured Items/Consumables/Buffs/Route/Meta screenshots (stale since
before this sub-slice) plus the new buff picker popup against a live
local ACE, isolated ACDREAM_CONFIG_DIR/ACDREAM_DATA_DIR (fresh authored
window positions, no stale-persisted-layout override), and an
ACDREAM_UI_PROBE_SCRIPT route through the five changed tabs. All six
confirm plain controls, no overlapping captions, correct grid rendering,
and real DAT move-icon art. Records the three S7.4-S7.6 commit SHAs and
their deviations in the ledger.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Records the merge + three fix-round-A commits (grid scaling/Profiles
cleanup/popup split, the App.csproj plugin-copy-target bug, the
StartVisible visibility fix + duplicate-title cleanup), the real
DAT-font measurement that superseded the 07:55 lead's row-pitch theory,
and the carried CopyTo-naming deviation for the next reviewer.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Brings cfa703065's owner-driven fix (plugin <menu> renders VTank's plain
flat combo by default; style="retail" opts back into the gold pushbutton
art) into the S7.1-S7.3 window/tabs work so the fix round below can build
on both. Resolved conflicts: the ledger keeps both worktrees' entries in
chronological order (07:55/08:05 owner-read entries appended after this
worktree's own S7.1/S7.2/S7.3 entries); plugin-ui-markup.md's <menu> row
lists both new attributes (scroll, style); MarkupDocumentTests.cs keeps
both new test blocks (slider min/max + menu scroll from this worktree,
menu style from latest-main-sync).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Records commit 57ced0aff (the VTank 23-column Monsters grid) in the
slice-7 ledger, including the Weapon/Offhand roster-cycle deviation and
the full-suite pass counts.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
N4 + summary: /status and /quit are console-intercepted verbs (they
never reach ChatCommandRouter), unlike @status which is a real server
command and still passes through untouched. Records the full S1-S7/
N1-N5 fix-round outcome, final Headless (207/1/208) and App LaunchOptions
(4/4) suite counts, and the one-commit-per-item/mutation-shown-to-fail
discipline used throughout.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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>
Owner amendment 2026-09-06: MossTank implements the human-readable metaf
.af format for metas and nav routes instead of VTank's binary .met/.nav;
the reference converter lives in the owner's metas repo. Docs 06 §1/07 §1
stay as the binary record; their semantics sections remain the oracle.
Doc 07 spot-checked by the lead: ExpressionEvaluator.cs:787-790 (';'
returns the first operand), hn.cs:41-80 (the pass loop), bw.cs:25 (the
'> 5' six-view cap), d6.cs:7-8 (Button/Layout only).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Owner direction 2026-09-06: decompile VTank, VirindiViewService and Classic
Looter (done, under refs/, gitignored), write the full catalog with citations
before implementing, keep file compatibility (.usd/.met/.nav/.utl), use our
native UI with VTank's own view XML as the layout truth (VVS not ported), and
keep everything Linux-clean. Also records the arbitration commit c406942ef in
its plan ledger; VT2 re-judges it against the catalog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Owner request 2026-09-06: the macro must use the Items profile to wield what
it needs, enter the right combat mode by itself to buff or fight from peace
mode, and return to peace when idle with Peace Mode When Idle on. Verified
gap: ACE drops any cast outside magic mode, and the buff pass never enters
magic mode or wields a caster; idle-peace lives only inside the combat
controller and so never runs with combat disabled.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Split the two hermetic RetailMarkupIconResolver memoization tests (and
their counting fakes) out of the Lane=InstalledDat class into a new
untagged RetailMarkupIconResolverMemoizationTests.cs so CI's portable
filter (Lane!=InstalledDat) actually runs them.
- PluginSidePanel: move the entry button's Anchors = AnchorEdges.None from
the Add() call site into PluginShelfButton's own constructor (same
comment carried over) so a second construction path cannot miss it.
- UiRectOutlinePainterOrderTests: assert the back panel's border segment
carries exactly 4 quads (24 vertices, FloatsPerVertex each) so a partial
outline cannot pass the painter-order check.
- RetailMarkupIconResolver: document the type as UI-thread-only (every
caller is a draw-time icon source) and bound the MISS cache to 256
entries with FIFO eviction — HIT entries stay unbounded (bounded by the
DAT's own surface count already). New test proves the 257th distinct
miss evicts the first (re-probe count rises); verified failing first
against the un-bounded code (Expected 258, Actual 257) before restoring
the fix.
- docs/plugin-ui-markup.md: split the icon-binding row's failure mode into
Build-time (missing property only — the binder never checks CLR type)
vs. draw-time (a resolved value that cannot convert to a number throws
from the draw, not from Build).
- docs/ISSUES.md: filed #486 (credits picture scroll frozen by the
per-draw anchor pass) and #487 (radar compass tokens candidate, same
mechanism, unconfirmed); corrected #461's causality — the graceful
logout/reveal-cancel log lines are printed by LiveSessionController.Tick's
catch -> StopAfterFailure -> StopCore AFTER the motion-update exception,
then it rethrows, so the logout is a consequence of the crash, not its
cause; real chain is the #462 stalled login-reveal materialization
leaving PlayerMovementController in RuntimeOwnedDormant outside its
SetPosition ground phase when an inbound 0xF74C arrives.
- Plan doc: recorded the three fix-round commits' verdicts (all PASS) and
the Smoke-plugin cleanup commit SHA in the Review ledger, plus a pointer
to the two newly filed issues.
Verified: dotnet build AcDream.slnx -c Release (0/0), targeted filter
85/0/0, full App suite 7364 passed / 97 skipped / 36 failed (36 pre-existing
InstalledDat/Manual/Linux-only failures, unchanged by name from baseline;
net +1 passed test from the new eviction test).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Owner direction 2026-09-06: the owner visually accepted all three connected
gates from the plugin-shelf/DAT-icon work — the movable plugin shelf
(Slice A), the DAT icon markup (Slice B), and the retained-UI outline-order
fix (761a7519f). With that gate passed, the Smoke plugin's job as the gate
artifact is done, so it is deleted outright rather than merely hidden:
src/AcDream.Plugins.Smoke/ (SmokePlugin.cs, SmokeIconPanel.cs, csproj, lock
files).
Reference sites cleaned:
- AcDream.slnx: removed the project entry.
- src/AcDream.App/AcDream.App.csproj: removed the Smoke ProjectReference and
the CopySmokePluginToBuildOutput/CopySmokePluginToPublishOutput targets;
the MossTank equivalents are untouched.
- .github/workflows/headless-portability.yml: the Linux package-contract
step no longer asserts a Smoke plugin.dll/plugin.json pair — repointed at
MossTank's, since the step's job was to prove the plugin-copy packaging
mechanism works end to end, not specifically to prove Smoke.
- tests/AcDream.Core.Tests/Plugins/PluginManifestTests.cs: the inline JSON
fixture used Smoke's manifest values as arbitrary test data; swapped for
MossTank's so the parser test still proves the same thing.
- tests/AcDream.App.Tests/Rendering/LinuxPlatformBoundaryTests.cs: the
shipped-plugin-copy shape test counted 4 GetTargetPath targets (Smoke +
MossTank, build + publish); now 2 (MossTank only).
- tests/AcDream.App.Tests/Plugins/AppAutomationSurfaceIconInstalledDatTests.cs:
reworded a doc comment that named the now-deleted SmokeIconPanel.
- README.md, docs/plugin-ui-markup.md: dropped Smoke-specific mentions,
kept the icon markup example/grammar (now citing MossTank's own real
IconSurfaceId).
- docs/plans/2026-09-06-plugin-shelf-and-dat-icons.md: recorded the owner's
2026-09-06 acceptance and the Smoke removal in the review ledger; deleted
the now-moot "before shipment" Smoke-in-release-zip warning.
- docs/reviews/coverage-ledger.md, docs/reviews/findings-ledger.md: left
untouched — both are frozen audit snapshots ("complete for baseline
<hash>"), so their Smoke rows are historical record, not live claims.
- docs/ISSUES.md: left untouched — its Smoke mentions are inside closed
issue #193's historical write-up of a past investigation.
MossTank plugin shelf icon: MossTankPlugin.cs's PluginPanelDescriptor now
sets IconSurfaceId = 0x06002C41 (IconText = "MT" remains the fallback).
Verified against the installed retail DAT with a new InstalledDat-lane test,
tests/AcDream.App.Tests/UI/MossTankIconInstalledDatTests.cs, mirroring
RetailMarkupIconResolverInstalledDatTests's convention: confirms the id is a
real Portal/HighRes RenderSurface and that RetailMarkupIconResolver.ResolveDid
returns a non-zero texture for it.
Verified: dotnet build AcDream.slnx -c Release green; a stale
plugins/AcDream.Plugins.Smoke output folder from a prior build was deleted
and a fresh build does not recreate it. Full App suite: 7,363 passed / 97
skipped / 36 failed (was 7,362/97/36) — the failing set is unchanged and
none are plugin-related; the one new pass is the MossTank DAT-icon test.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bounded residual round on the Slice B review fix commit (466272ec5),
docs/plans/2026-09-06-plugin-shelf-and-dat-icons.md.
N1 (BLOCKING): PluginSidePanel's shelf entries resolved icons through
_bindings.Assets.ResolveSprite (= ResolveChrome =
TextureCache.GetOrUploadRenderSurface), which returns a non-zero 1x1
magenta placeholder for a missing id - so PluginShelfButton's initials
fallback could never fire in production. RetailUiRuntime.MountPlugins
now passes the same iconResolver.ResolveDid every markup icon sink
already uses, which returns (0,0,0) for an unresolvable id. Re-pointed
the existing initials-fallback unit test at a resolver matching
ResolveDid's real contract, and added an InstalledDat-lane test
(ShelfButton_BogusDescriptorId_OnTheRealResolver_FallsBackToInitials)
proving a bogus descriptor id on the REAL resolver yields initials.
N2: MarkupDocument's <button icon>/<list icons> handling only built the
uint reader (BindUintLiteralOrBinding/BindUintList) when an
IMarkupIconResolver was wired, so a malformed icon="{Typo}" or
icons="notabinding" silently loaded instead of throwing at Build on a
resolver-less host. Both readers now build unconditionally (same rule
ValidateIconKind already followed); only the IconSource/IconIdsSource
assignment stays gated on icons is not null.
N3: a negative bound icon id threw OverflowException out of
Convert.ToUInt32 every frame from inside UiSimpleButton.OnDraw (scalar
path), while the list's IEnumerable<int> path silently wrapped -1 to
0xFFFFFFFF (unchecked reinterpret). Both paths now map any
out-of-range value (negative, or above uint.MaxValue) to 0u instead -
Decal's own "no icon" convention - via a shared ToUintOrZero helper
that catches exactly the OverflowException Convert.ToUInt32 already
throws for both cases.
N4 (perf): RetailMarkupIconResolver.ResolveDid probed Portal/HighRes
(two cache misses + two B-tree lookups under the database lock) on
EVERY call for an unresolvable id, and re-entered the DAT lock on
every resolve of a hit too. Memoizes the resolved (tex,w,h) tuple per
DID, including the (0,0,0) miss, in a plain Dictionary.
N5 (nit): documented in TextureCache.GetOrUploadRenderSurface that the
(id, nearest) cache key uploads the same RenderSurface twice when both
samplers are wanted (chrome via ResolveChrome, plugin icons via
ResolveDid's nearest:true) - GetOrCreateLinearUiTwin exists but only
shares in the nearest-registered-first direction, so wiring it through
here is left as a documented nit rather than a behavior change.
N6 (nit): corrected stale SampleData.cs:64 citations to :69 (Melee
Defense's real line after the file grew) across SmokeIconPanel.cs,
PluginSidePanelTests.cs, RetailMarkupIconResolverInstalledDatTests.cs,
and docs/plugin-ui-markup.md (including the 64-82 range, now 69-83).
N7 (nit): <icon iconkind="..."> was silently ignored (icon derives its
kind from which of did/spell/item is set, unlike button/list). Now
throws FormatException at Build with a message naming the correct
surfaces; documented in plugin-ui-markup.md.
N8 (nit): the truth-table's `list colors` row now says IEnumerable<uint>
or IEnumerable<int> (shared BindUintList), matching `list icons`.
N9 (ship check): added a "Before shipment" line to the plan's Review
ledger. Confirmed the Smoke plugin (including its auto-open Icon Smoke
panel) IS included in the launcher's client-<rid>.zip release payload:
tools/publish-bin.ps1's New-PayloadZip zips App's entire publish
directory unfiltered, and AcDream.App.csproj's
CopySmokePluginToPublishOutput target runs unconditionally
AfterTargets="Publish". No behavior changed per instruction - flagged
for follow-up after the owner's connected gate.
Verification: dotnet build AcDream.slnx -c Release green; filtered
test command 108/108 passed (0 skipped) including the InstalledDat
lane; full AcDream.App.Tests suite 7362 passed / 97 skipped / 36
failed (all 36 pre-existing, same names, none touching
Markup/PluginSidePanel/RetailMarkupIconResolver/TextureCache/PluginIcons);
AcDream.Plugins.MossTank.Tests 337/337 passed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>