Commit graph

2725 commits

Author SHA1 Message Date
Erik
2b79ca3257 docs(vtank): slice 7 ledger — round D landed (items 1-4)
Records the merge of claude/latest-main-sync-497549 plus round D's
four fix items (Advanced Options category names, VTank's click model,
the full 26-recall table, resizable/enlarged main panel) on the panel
worktree, with commit SHAs, test-count deltas, and the carried
deviations (#491, the RouteRecallKind-ordinal migration risk).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 17:25:48 +02:00
Erik
4ba0a557f6 merge(vt): bring in retail scrollbar chrome + resizable/anchor markup
Merges claude/latest-main-sync-497549 into the slice-7 panel worktree
so round D can build on both: b71a8ea37 (retail scrollbar chrome on
plain <menu> popups and overflowing <list>s — chat/inventory sprite
ids, always-scrollable single-column menu) and 2e63391cc (<panel
resizable minw minh> + anchor="left top right bottom" markup).

Conflicts resolved keeping both intents:
- Ledger (docs/plans/2026-09-07-campaign-vt-slice7-tabs.md): unioned
  both branches' entries into one chronological timeline instead of
  picking a side.
- docs/plugin-ui-markup.md: kept both attribute additions per element
  (slider min/max/style, menu scroll/style) AND anchor on every row.
- src/AcDream.App/UI/UiMarkupList.cs: kept this branch's fix round B
  item 10 (VVS HudList grids have no row-selection highlight) over the
  sync branch's older SelectedColor band draw in the <column> grid
  path — the legacy single-column list path is unaffected either way.
- src/AcDream.App/UI/MarkupDocument.cs: the auto-merge left two
  `Scrollable =` initializers on the same <menu> object (CS1912).
  Kept the sync branch's `Scrollable = true` (VTank's HudCombo is
  always a single scrolling column, never a wrapping grid) and
  dropped this branch's `Scrollable = B(el, "scroll", false)` opt-in,
  since the owner-driven always-scrollable design supersedes the
  S7.2 opt-in one. Updated MarkupDocumentTests.cs to match: removed
  Build_MenuWithNoScrollAttribute_KeepsScrollableFalse (asserted the
  now-false opt-in default) and
  Menu_Scroll_DrawsAPlainFlatThumbFillWhenTheMarkupItemCountOverflowsTheVisibleRows
  (asserted a flat DrawFill thumb; the scrollbar is sprite-chrome for
  every menu style now) — both fully superseded by
  Menu_Markup_IsAlwaysScrollable_WithRetailScrollbarChromeWired and
  UiMenuPlainStyleTests.Plain_OpenPopup_ScrollableOverflow_
  DrawsRetailScrollbarChrome_RowsStayPlain.

Verified: dotnet build AcDream.slnx -c Release green; MossTank suite
678/678; App markup/plugin filter 242/242 (241 before this commit's
test-file trim, +1 net from the merge's own new tests, 0 red).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 16:01:51 +02:00
Erik
9eeabb481d docs(vt): slice 7 ledger — fix round C landed; round D dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:49:48 +02:00
Erik
6b42fd68ed test(vtank): slice 7 fix round C item F13 — drop the control-count change detector
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>
2026-09-07 15:46:33 +02:00
Erik
e2cca20e23 docs(vt): slice 7 ledger — scrollbar chrome and resizable/anchor markup merged; round D queued
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:45:34 +02:00
Erik
2e63391cc4 merge(vt): resizable plugin panels (resizable/minw/minh) and anchor markup (owner: larger default, resizable)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:45:06 +02:00
Erik
b71a8ea377 merge(vt): retail scrollbar chrome on plain <menu> popups and overflowing <list>s (owner: same assets as chat/inventory)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:44:26 +02:00
Erik
c7fbbc5608 docs(ui): document resizable panels and anchor grammar
Adds the "Resizable panels and anchors" section to plugin-ui-markup.md:
the resizable/minw/minh attribute table for <panel>, the anchor grammar
for every element that now supports it, the AnchorEdges semantics
(left top default, left right / top bottom stretch, right/bottom pin-
and-move), group-relative child anchoring, and one worked example
(a resizable panel with a group and list that both stretch on drag).
Also updates the Elements table, the "every registered window" intro
paragraph, the ApplyCommon common-attributes paragraph, and the Testing
conventions section to reference the new grammar and its test coverage.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:43:28 +02:00
Erik
e9108277c4 feat: retail scrollbar chrome for markup <menu> overflow and <list> overflow
Owner live-client report 2026-09-07: "For scrollable dropdown or the meta
window we use the same assets as we do in for example chat or inventory
window."

<menu> markup wiring (MarkupDocument.cs): a plugin <menu> is now always
Scrollable (single-column, VTank HudCombo shape) instead of wrapping
overflow into more grid columns, with PopupScrollbarHideWhenDisabled=true
so the bar is entirely absent while the item count fits the "rows"
window. RetailScrollbarChrome.ApplyToMenuPopup wires the same chrome ids
the previous commit taught DrawScrollablePopupPlain to draw, for both
style="plain" and style="retail" markup menus.

<list> markup (UiMarkupList.cs / MarkupDocument.cs): a plugin <list>
(single-column or <column> multi-column) that overflows its own row
viewport now draws the retail scrollbar chrome at its right edge (VVS's
own placement, 16px wide) instead of being wheel-scroll-only with no
visible bar. The reserved 16px column only exists while rows actually
overflow, in both column-layout modes (ComputeColumnLayout receives the
already-shrunk width so the last/auto column absorbs the remainder
correctly); the bar is fully interactive (up/down arrows, track paging,
thumb drag) via a small UiScrollable projection kept in sync with the
list's own _topRow, which stays the single source of truth. Wheel
scrolling and a no-resolver hand-built list (draws nothing, no crash) are
unchanged.

Mutation shown to fail first: new
UiMarkupListScrollbarTests/MarkupDocumentTests cases were written against
pre-change UiMarkupList/MarkupDocument and failed (no scrollbar sprites
ever emitted since UiMarkupList had no SpriteResolve property at all, and
<menu> markup never set Scrollable) before the implementation landed;
after: SingleColumn_Overflowing_DrawsRetailScrollbarChromeAtRightEdge and
Columns_Overflowing_ReservesSixteenPixels_LastColumnShrinksAccordingly
pin sprite ids + exact reserved-width geometry,
*_ContentFits_DrawsNo(Scrollbar|ReservationLastColumnKeepsFullRemainder)
pin the no-overflow/no-bar case, *_UpArrowClick_ScrollsUpByOneRow and
ThumbDrag_MovesTopRowAndIsReadableByASubsequentClick pin interactivity via
a following row click resolving to the moved position (mirroring
MarkupListColumnsTests' own wheel-scroll pin), and the four new
MarkupDocumentTests menu cases pin Scrollable/PopupScrollbarHideWhenDisabled/
the six chrome-id properties plus an end-to-end open-popup draw for both
the overflowing (draws chrome) and non-overflowing (draws none) cases.
Every pre-existing MarkupListColumnsTests/MarkupDocumentTests case stays
green unchanged (none of their fixtures overflow their own viewport).

docs/plugin-ui-markup.md updated: the <menu> style paragraph and a new
<list> "Scrollbar" section describe the new chrome + auto-reservation, and
the PITCH-transcription guidance is corrected to say the 16px scrollbar
column is now automatic (no more manual fold-in/double-reservation advice).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:43:00 +02:00
Erik
bc273adcbd docs(vt): slice 7 ledger — owner's live look; App-side scrollbar/resizable work dispatched; panel round D queued
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:17:12 +02:00
Erik
b36b036475 docs(vt): slice 7 ledger — round B closed at 16/18, arch re-check verdict, round C dispatched, owner testing live
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 14:48:37 +02:00
Erik
da42c1fce6 feat(app): slice 7 fix round B item 11 — plain <slider> style, mirroring <menu style>
Plugin markup's <slider> always drew RetailScrollbarChrome's sprite
track/thumb, the same "big gold DAT art next to a plain plugin panel"
mismatch <menu style> already fixed for dropdowns. <slider style="..."> now
uses the identical plain/retail grammar (ValidateArtStyle, renamed and
generalized from the menu-only ValidateMenuStyle): plain (the default)
draws a flat dark track, 1px border, and a small flat nub via new
UiScrollbar.RetailArt=false + DrawPlainScalar — no SpriteResolve dependency
at all; style="retail" keeps RetailScrollbarChrome.ApplyHorizontal exactly
as before. RetailArt defaults to true on UiScrollbar itself, so every
non-plugin caller of this widget (retail LayoutDesc import, chat opacity
sliders, etc.) is byte-for-byte unaffected — only <slider>'s own
MarkupDocument case sets it false by default.

Every existing MossTank <slider> (Vitals' nine sliders, Buffs, Items'
Refill Worn Mana) has no style attribute, so they all switch to the plain
look automatically — consistent with the whole campaign's "no gold art"
direction, no XML changes needed.

Fixed a red pin this change created: Slider_MinMax_DrawsTheThumbAtTheRescaledNormalizedPosition
asserted the retail sprite thumb on a slider with no style attribute, which
now builds plain by default — opted it into style="retail" (same fix
shape as item 1's menu-scroll pin) and added a plain sibling,
Slider_NoStyleAttribute_DrawsAPlainFlatNubAtTheRescaledNormalizedPosition.
Mutation check: hardcoding DrawPlainScalar's horizontal nub x to 0 turned
the new plain test red ("expected a plain flat nub offset right of the
origin at 25%"); restoring the real ScalarPosition-driven x turns it green.

Documented <slider style> in docs/plugin-ui-markup.md, mirroring the
existing <menu style> paragraph.

tests/AcDream.Plugins.MossTank.Tests: 671/671 (unchanged — pure App-layer
rendering change, MossTank markup only sets no/default style).
tests/AcDream.App.Tests --filter Markup|Plugin|UiMenu|Slider: 278/3 skipped/281 (was 277/3/280, +1 new test).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 13:09:33 +02:00
Erik
e6e47dd98a docs(vt): post-campaign idea — readable export/diff for settings and loot, not a second storage format
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 11:51:14 +02:00
Erik
c62dc495a5 docs(vt): slice 7 ledger — both review verdicts, lead decisions, fix round B dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 11:13:00 +02:00
Erik
805d10e2b8 docs: file #490 (plugin-panel host StartVisible/ShowInSidePanel + layout revision) and #491 (buff lists not consumed by BuffPlan.Build)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 11:12:40 +02:00
Erik
327e0e93df docs(vt): slice 7 ledger — all nine tabs landed; lead's read of Route/Meta for fix round B; reviews dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 10:55:58 +02:00
Erik
dbdde0783d merge(vt): plain <menu> popup from the campaign branch into the slice-7 panel work (ledger union)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 10:54:25 +02:00
Erik
41fc1d88d1 docs(vt): slice 7 ledger — S7.4-S7.6 landed, fresh live screenshots
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>
2026-09-07 10:51:55 +02:00
Erik
fd5dfa49e0 docs(vt): document that plain <menu> style covers the open popup too
Follow-up to the UiMenu popup fix: the existing "menu style" paragraph in
plugin-ui-markup.md only described the closed-state button face swap from
the earlier S7 fix. Extend it to say the plain style now covers the whole
menu (closed AND open) — flat popup chrome matching <list>, a lighter hover
fill, no checkmark, and a plain scrollbar past the row cap — so a plugin
author reading the doc doesn't assume style="plain" only affects the
closed face.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 10:19:54 +02:00
Erik
fab134ae4f docs(vt): slice 7 ledger — owner: the open dropdown is still retail art; plain popup dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 09:55:44 +02:00
Erik
422ca75172 docs(vt): slice 7 ledger — fix round A landed, remaining tabs dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 09:55:03 +02:00
Erik
66b070def4 docs(vt): slice 7 ledger — fix round A landed, four commits recorded
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>
2026-09-07 09:50:54 +02:00
Erik
78b42a519e fix(vtank): popup panels actually show; drop duplicate popup titles; fresh screenshots
Live-verified two real defects the previous commit's design didn't catch
without a running client:

1. Both new popups (mosstank-advanced.xml, mosstank-loot-editor.xml) were
   registered with StartVisible=false, on the theory that the markup's own
   visible="{AdvancedOptionsVisible}"/"{LootEditorVisible}" binding would be
   the sole gate. It is NOT: RetailUiRuntime.MountPlugins wraps every
   plugin window's markup availability in a PluginWindowVisibilityController
   that ANDs it with a SEPARATE "requested visible" axis seeded from
   StartVisible, flipped back to true only by OnShown() — the shelf's
   un-minimize click. A ShowInSidePanel=false window has no shelf entry to
   click, so StartVisible=false left "requested visible" permanently false
   regardless of the markup binding, and both popups never rendered no
   matter how many times the checkbox was toggled (confirmed live: checkbox
   showed checked/green, no window appeared). Fix: StartVisible=true, which
   keeps "requested visible" true from construction (OnHidden only ever
   latches it back to false on a genuine minimize, explicitly no-opping
   when the hide was caused by availability itself going false — exactly
   what closing via "Back" does), leaving the markup binding as the sole
   effective gate, same as the main panel's own always-true
   ShowInSidePanel=true default.

2. Once visible, both popups showed garbled overlapping text at their top
   edge ("AdvancedOptionsced Options — complete VTank settings table",
   "Loot profileRules(first match wins)"): each file's own in-content
   descriptive label duplicated the window's OS-level title bar
   (MarkupDocument.Build auto-renders <panel title="..."> at a fixed (8,4)
   — the exact corner the in-content label used to own back when these
   were in-panel groups with no title bar of their own). Fix: dropped both
   redundant labels; the window's own title ("Advanced Options" caption
   duplicated as "MossTank Advanced Options"/"MossTank Loot Editor") is now
   the only thing there.

Also repositioned both popups' default (x,y) from the placeholder
(440,60) — which overlapped the main panel — to (253,405)/(660,405),
below the main panel, side by side, both fitting within a 720-tall client.

Screenshots recaptured end to end against a live local ACE
(127.0.0.1:9000, testaccount/+Acdream) with the rebuilt Release exe from
this worktree, using an isolated ACDREAM_CONFIG_DIR/ACDREAM_DATA_DIR (no
stale persisted window layout from earlier probe runs — RetailWindowLayoutPersistence
keys plugin windows by name with authoredGeometryRevision=0, so a
previously-opened window's persisted x/y wins over any new authored
default forever; using a scratch config directory sidesteps that rather
than editing the real %APPDATA%\acdream\settings.json). tab-options.png,
tab-profiles.png, tab-vitals.png, and tab-monsters.png confirm the fix
round A grid-scaling and Profiles-cleanup commit's fixes hold on a live
client (no overlap, no gold buttons, no stacked New buttons, no dead
window space); popup-advanced.png and popup-loot-editor.png confirm both
popups now open as genuinely separate windows with clean single titles and
working move-up/move-down DAT icons (no blank button slots).

MossTank suite still 654/654; App markup/plugin/menu filter still
237/237 (no test changes in this commit — the earlier commit's
SecondaryPopupPanelsFitTheirOwnBoundsAndEveryBindingResolves already
covers both files' structure and bindings, and neither the visibility
seeding fix nor the label removal changes what those pins check).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 09:49:32 +02:00
Erik
80dc762375 docs: headless console CLOSED — connected proof passed; #489 gains the diagnostics-interleave polish item
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:30:35 +02:00
Erik
39ed2b5f95 docs: file #489 — headless SpewBox growth without a console, plus console polish items
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:27:48 +02:00
Erik
8cb284d6f7 merge: headless console — interactive chat/command CLI for the bot host (review-closed)
Owner direction 2026-09-07. Reader thread → tick-drained queue, the same
ChatCommandRouter.Submit the chat box uses, event-stream renderer,
SpewBox pump, --console / ACDREAM_HEADLESS_CONSOLE (=0 disables).
Opus review APPROVE-WITH-FIXES, 12-item fix round, narrow re-check
MERGE-READY.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:25:22 +02:00
Erik
66160741f0 merge: plugin text and unknown-command refusals go to the chat window (owner-directed, AD-124)
Owner 2026-09-07: plugin output and 'Unknown command' land in the chat
scroll, not the SpewBox. Plugin text = Decal/VTank-faithful; the
unknown-command re-route is recorded as AD-124 (retail types it 0x1A).
Bad-argument refusals of real retail commands stay SpewBox-only (AP-183).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:24:02 +02:00
Erik
045cd0a195 merge(vt): plain <menu> style from latest-main-sync into slice7 panel work
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>
2026-09-07 08:23:29 +02:00
Erik
6b7b4bb213 fix #363/#367: route unknown-command refusals to chat, not SpewBox
Owner direction 2026-09-07 (verbatim): "Unknown commands like /vt or
stuff from plugins shall now go to the SpewBox. They should go to the
chatbox." Retail itself types ChatCommandRouter's "Unknown command"
refusals as ClientLocal (0x1A) -- the bit every ChatInterface window's
default filter excludes, so they only ever reached the transient
SpewBox overlay and left no transcript record.

Three call sites in ChatCommandRouter.Submit/EmitVerbHelp now call
IChatCommandFeedback.ShowSystemMessage (chat scroll, retail
Default/0x00) instead of ShowInterfaceText (SpewBox): the degenerate-
prefix "Unknown command: {verb}." guard, EmitVerbHelp's confirmed-
null-help branch, and EmitVerbHelp's unresolved-verb fallback. Every
OTHER 0x1A refusal in this file (AP-183 bad-argument refusals of REAL
retail commands -- lifestone, marketplace, channel list/on/off,
allegiance, house, the generic HandleFailureEvent(0x26) fallback,
DoStupidChannelHack, DoReply) is unchanged and still SpewBox-only --
the owner named only unknown commands and plugin text.

This is a deliberate deviation from retail's own 0x1A typing, recorded
as register row AD-124 (also covers the sibling plugin-text change in
a follow-up commit). docs/ISSUES.md #363/#367 get a one-line note
under each pointing at the re-route; their CLOSED status is untouched.

Mutation check: temporarily reverted all three ShowSystemMessage call
sites back to ShowInterfaceText and confirmed the 3 new/changed pinned
tests fail (Assert.Single() on an empty chat log) while the AP-183
boundary test (real command, bad args, still SpewBox) continues to
pass -- see ChatCommandRouterFeedbackRoutingTests.cs and the updated
ChatCommandRouterTests.cs/RetailCommandHelpTableTests.cs assertions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:22:06 +02:00
Erik
47a1fe555c docs(vt): slice 7 ledger — Monsters landed; fix round A dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:20:10 +02:00
Erik
c3b4f78624 docs(vt): slice 7 ledger — S7.3 Monsters grid landed
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>
2026-09-07 08:18:37 +02:00
Erik
7381112394 docs(headless-console): record the 2026-09-07 Opus fix-round ledger entry
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>
2026-09-07 08:15:35 +02:00
Erik
d8846d7a2d docs(vt): document <menu style> in plugin-ui-markup.md
Adds style to the <menu> attribute row and one sentence explaining why
plain is now the default (owner report: retail's gold pushbutton art
read as an out-of-place button next to a plugin's own dark list boxes)
and what style="retail" opts back into.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 08:15:32 +02:00
Erik
1637bae31d docs(vt): slice 7 ledger — owner's live look: overlaps and the gold dropdowns must go
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:56:49 +02:00
Erik
d1fe52368d docs(vt): slice 7 — live screenshots of S7.1/S7.2 (cropped) and the lead's read for the fix round
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:54:27 +02:00
Erik
55e454aedc fix(headless): S1 ACDREAM_HEADLESS_CONSOLE=0 disables even on a real terminal
HeadlessConsoleOptions.Resolve tested the environment variable against
the literal "1", so ACDREAM_HEADLESS_CONSOLE=0 silently fell through to
the terminal-shaped default (on when stdin is a real console) instead of
acting as an A/B off-switch. Now: once the variable is SET AT ALL, any
value other than "0" enables and "0" disables -- the same idiom
ACDREAM_RETAIL_CLOSE_DEGRADES / ACDREAM_RETAIL_UI already use. An unset
variable still falls through to the terminal default.

Registered the flag as the sixth entry in
LaunchOptionsDocumentationTests.DefaultOnBehaviorFlags and updated the
Conventions section of docs/launch-options.md plus the flag's own row
(side-effects column corrected to describe the real precedence).

ResolvePrefersFlagThenEnvironmentThenTerminalDefault's env="0"/terminal
=true case was shown to fail against the prior `== "1"` implementation
(expected false, old code returned true) before the fix landed; the
env="yes" case also failed on the same mutation (old code required the
literal "1", so "yes" fell through to terminal=false instead of enabling).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:51:41 +02:00
Erik
9ec145173e docs(vt): slice 7 ledger — ACE was up; the TCP probe was wrong (ACE is UDP)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:37:21 +02:00
Erik
8681a25e6c docs(vt): slice 7 ledger — S7.1/S7.2 landed, popup-height note, screenshots owed (ACE down)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:28:59 +02:00
Erik
89a49836ca docs(vt): slice 7 ledger — S7.1/S7.2 landed, screenshots skipped (ACE down)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:27:03 +02:00
Erik
e72a64a311 feat(ui-markup): slice 7 step 1 — <slider min max> and <menu scroll>
Campaign VT slice 7 needs to transcribe VTank's own Vitals sliders
(minimum=0/maximum=100) and its long Profiles/Route named-item combos
control-for-control (docs/research/vtank-kb/08-ui-views.md §3's two
markup gaps). acdream's <slider> was hardwired to a 0.0-1.0 scalar and
<menu> always wrapped overflow into extra columns instead of VVS's
single scrolling column.

<slider min max>: optional literal attributes declaring the range the
bound value/onchange speak in (e.g. min="0" max="100" for a percent),
while UiScrollbar itself keeps its existing 0.0-1.0 internal math
untouched — MarkupDocument rescales at the binding boundary. Omitting
both (every pre-existing <slider>) keeps the exact historical identity
range.

<menu scroll="true">: wires UiMenu.Scrollable plus the same
track/thumb/up/down chrome sprites ConfigOptionsPageController and
VendorUiController already apply to their own Scrollable menus,
previously only reachable from C#. Omitting scroll keeps the
historical column-wrapping default.

Both are additive — no existing <slider>/<menu> markup changes
behavior. New pins in MarkupDocumentTests.cs shown to fail against the
prior MarkupDocument.cs (5 failures: Build_SliderWithNoMinMax_*,
Build_SliderWithMinMax_*, Slider_MinMax_Draws*,
Build_MenuWithScrollAttribute_*, Menu_Scroll_Draws*) before this
change, all green after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:07:42 +02:00
Erik
97b1c9f6ce 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>
2026-09-07 06:57:05 +02:00
Erik
7bff9c649d feat(headless): typed --console option resolution + command-line flag
Adds the first piece of the interactive headless console (docs/plans/
2026-09-07-headless-console.md): HeadlessConsoleOptions.Resolve picks
--console, then ACDREAM_HEADLESS_CONSOLE=1, then a terminal-shaped
default, matching the project's typed-options-object convention rather
than a scattered env-var read. HeadlessCommandLine.Parse now accepts
--console as a bare flag (no value token) alongside the existing
paired options. Both new launch-options.md rows are added in this
commit per LaunchOptionsDocumentationTests' bidirectional rule.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:56:03 +02:00
Erik
fbdbbc7f90 docs(vt): slice 1c review D1 — the profile-dir override row and AD-122 say the first load moves flat .af files
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:54:00 +02:00
Erik
7cfe57827c merge(vt): slice 1c — metas/ and navs/ folders, no nav_ prefix (review-closed)
Owner decision 2026-09-07. Folder-scoped listing, one-time flat-file
migration, content sanity on load. Narrow Opus review: MERGE-READY.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:53:43 +02:00
Erik
615a401994 docs(vt): slice 7 visual gate script (draft, filled from KB 08)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:46:39 +02:00
Erik
812a533b83 feat(vtank): slice 1c step 1 — two-folder metas/navs layout, no nav_ marker
Owner decision 2026-09-07: Meta and Nav profiles both use metaf .af and are
told apart by living in two dedicated VtankProfiles subfolders (metas/,
navs/) instead of the flat-directory nav_/--nav_ marker scheme from slice 1
Part A, which was only ever how the owner happened to name files in their
own metas repo. VtankProfileDirectory.ListMetaProfiles/ListNavigationProfiles
now enumerate metas/ and navs/ respectively via a new folder-scoped
EnumerateFolderFileNames helper; the NavMarker constant and the marker
overload of AutoCharacterFileName are deleted. MossTankMetaProfileStore and
MossTankRouteProfileStore build every real storage key with their folder
prefix (CurrentFileName, Select, Create, TryImportLegacy, the legacy-roster
sweep) and strip it back off for display (StripAf/Strip). The .cdf's Nav/Meta
lines (4-5) now carry the folder-relative key ("metas/Name.af",
"navs/Name.af"); AD-122 and the ACDREAM_VTANK_PROFILE_DIR launch-option row
are updated to describe this.

Mutation demonstrated: reverting VtankProfileDirectory.cs,
MossTankMetaProfileStore.cs, and MossTankRouteProfileStore.cs to HEAD~ (the
flat nav_-marker layout) while keeping the updated tests reproduces 8 test
failures (KeyNotFoundException / Assert.True(false) against the new
"metas/…"/"navs/…" keys the tests now expect, e.g.
MetaSaveAcceptsAnAfSuffixedNameWithoutDoublingIt,
MetaAndRouteProfilesWithTheSameNameDoNotCollide,
NavCommandsImportLegacyAndExportAf, MetaCommandsImportLegacyAndExportAf,
MetaRosterSweepConvertsEveryNamedLegacyProfileOnce,
MetaStoreLeavesLegacyJsonUntouchedWhenAfCounterpartExists,
MetaStoreRefusesToSaveADisabledRuleAndKeepsThePriorAfContent,
NavSaveAcceptsAnAfSuffixedNameWithoutDoublingIt) — confirmed by running the
suite immediately after the production-code edit, before the test-file
updates landed. All 625 tests pass after both sides of the change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:32:56 +02:00
Erik
a427d7db05 docs: plan the headless console (interactive chat/command CLI for the bot host)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:32:47 +02:00
Erik
43abc32edf docs(vt): owner direction — one plugin, two hosts; slice 2 gains headless autostart + a headless MossTank smoke test
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:29:46 +02:00
Erik
074762dd36 docs(vt): slice 7 plan — the nine tabs at VTank's geometry on the column markup; pulled forward after slice 1
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:23:28 +02:00
Erik
aafa66c821 docs(vt): owner decision — metas/ and navs/ subfolders, no nav_ prefix
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 06:20:16 +02:00