Commit graph

763 commits

Author SHA1 Message Date
Erik
3d746294ae docs(issues): #464 owner's tilted frame with the walk transcript — same admission set, seventh exit view; the open face shows the hall interior where retail shows the shell wall
The frame is saved as logs/464-owner-tilted-frame.walk.txt. Narrowed to
the building shell versus interior-cell order/clip at the stairwell's open
face in the outside pass (S4), with a possible building-portal admission
component only the cathedral-stair-arch retail capture can settle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:19:17 +02:00
Erik
1be895f153 docs(issues): #464 walk transcript at the owner's pose — the hall cells are admitted through the building's exterior portals in the outside pass
The automation cannot tilt the camera, so the owner's screenshot stays the
record of the frame; the transcript shows the interior root flood of the
three stacked stair cells with six outside views and fifteen building-
portal groups including the hall cells. The retail capture at this pose
decides depth (S4) versus admission.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:09:06 +02:00
Erik
8d3eb12c4e docs(issues): #464 owner-confirmed artifact pose pinned with probes — ordinary camera state, hall interior drawn through the stairwell's open far face (S4)
Owner client with both probes: root 0xF4180114, eye (39.89,17.25,182.36),
sweep uncontacted; the hall's interior shows above the bottom arch where
retail shows the solid far face, which the DAT gives as five exit portals.
The retail capture cathedral-stair-arch is requested as the fix oracle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:07:25 +02:00
Erik
27ff6bb041 docs(issues): #464 — the front-view frame is a retail axiom (owner); the real artifact is toward the arches on the other side
Also commits the walk-transcript route used at that eye.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:55:11 +02:00
Erik
28da2fcb8e docs(issues): #464 reproduced from the script — camera in front, zoomed out through the open face into the hall; stairwell draws without walls
The eye is legitimate (retail's sweep passes the same opening); the defect
is the draw of the stairwell cells seen back through the building's
exterior portals. Matrix row invariant re-worded; the one retail capture
to request is the oh-capture walk + alphadepth at exactly this eye.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:54:18 +02:00
Erik
c3b989305a docs(research): #464 camera investigation report; reclassified as an interior-root draw defect (S4); archway route
Read-only decomp + real-DAT replay: eleven sweep/root differences, each
unreachable at the pose or more constrained than retail; the replay seats
the pivot in 0xF4180114, stops the boom on its east pier at y=16.448, and
the walk from that root floods 114/113/112 with seven exit views. The
owner's probe launch line now also sets ACDREAM_PROBE_FACILITY_STAIRS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:50:40 +02:00
Erik
060c392ecc docs(issues): #464 owner launch line — forward slashes (the previous line lost a path segment to an escape)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:41:26 +02:00
Erik
6ae511e11e docs(issues): #464 camera-cell probe rounds — the eye never leaves the cell; re-read as the exit-portal seam-band family
Four probe-on self-gate rounds (run/zoom/tilt/mid) with the camera cell,
root and eye logged every frame: sweep ok, eye in root, no fallback, in
every frame. The DAT shows 0xF4180113/0xF4180114 are one stairwell split
horizontally; the zoomed-out eye stops 0.31 m in front of 0x114's
nine-vertex EXIT portal. Owner asked for one probe-on reproduction.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:40:59 +02:00
Erik
36866ba663 docs(issues): #464 running reproduction (camera outside the stairwell at movement start); file #467 run-in-place at the corridor mouth
The held-forward route captured the owner's running symptom: the first frame
after the press has the chase camera above and outside the stairwell, the
next is clean. Same defect as the zoom-out. The runs also showed the
character running in place at one corridor spot for 5+ s (#467, movement,
outside the campaign).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:26:58 +02:00
Erik
20d844b06d docs: #466 owner-confirmed ours; ACViewer step dropped
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:11:17 +02:00
Erik
0bb9d1824a docs: file #466 — Ravenous Eater renders with stretched stripes and untextured patches (owner, /create 35121)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:08:54 +02:00
Erik
cddd3d236b docs: file #465 — post-campaign panel fill for retail's cathedral seam leak, with the regression guards and A/B acceptance
Owner decision 2026-09-03: an improvement on retail, deferred until G4
passes; retail mode off; registered when built.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:02:06 +02:00
Erik
455de7f24d docs(render): owner S3 double-check — all poses PASS except the zoomed-out cathedral stairwell (#464); matrix row added
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:40:58 +02:00
Erik
6c7512de15 docs(render): ledger — E1 re-measured same-session: every stationary destination within 1.14x, chunk 3 back to CLOSED; file #463 (soak turn-sample artifact)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 19:09:03 +02:00
Erik
6435655d73 docs: S4 packet — particles take the retail DrawMesh branch table; #459 names the unconsumed-attribute candidates
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:14:57 +02:00
Erik
cf39dab811 docs: #459 resolved with validation proof; ledger notes the fix and the S4 draft
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:13:15 +02:00
Erik
7553ff3c5e docs: file #461 (motion update after logout crashes on the retired movement controller) and #462 (intermittent interior login reveal stall)
Both found by the G3 self-gate part C at 2fbfdf18a; evidence paths and the
sequence lines are in the entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:06:09 +02:00
Erik
2fbfdf18a8 docs: file #460 — windowless shutdown hang after an aborted automation script at the Nanto pose
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:41:56 +02:00
Erik
e18b9d0939 docs: file #459 — five fragment shaders declare DemoteToHelperInvocation without the device feature
Found by the first validation-layer self-gate (S3 chunk 4 round 2). The
capability set is identical on the tip and the round-2 worktree, so it
predates chunk 4; the fix (enable the 1.3 feature or pin the compiler's
target to SPIR-V 1.5) gets its own commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 15:42:02 +02:00
Erik
37e42aafc4 docs(render): resolve #458 — the a9c9 doorway admission is a 0.5 % edge-plane precision boundary (AD-118)
Two live cdb captures on the paired 2013 client at the Holtburg doorway:
the blockset template (every Render::block_check call of one frame — 2,601
resident blocks x 2 exit views) proves retail tests a9c9 at ring slot
25,46 and returns PARTIALLY then OUTSIDE; the blockcheck template dumps
its four corner interval vectors (0 0 0 0 300.4|310.2 and 0 0 0 1001 ...,
slab 75..330). acdream's replay at the same P pose reproduces the sentinel
pattern, the four edge planes and both verdicts, drawing a9c9 once, with
clip heights 298.8/308.5 m — a 0.5 % plane difference (about 0.35 px of
projected door-vertex position). At the fixture pose that margin is what
flips the south-west corner from inside to outside on the fourth edge
plane, so retail's four-corner unanimity test says OUTSIDE where ours
says PartiallyInside. Not fixable bit-exactly short of D3D's x87
transform; the KnownFailure row stays with its comment rewritten, the
register carries AD-118, and the first filtered capture's silent miss
(cdb sign-extends poi() inside .if; use dwo()) is noted in the template.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 14:43:14 +02:00
Erik
7104b8e588 docs(issues): #458 — block test structurally identical to retail; next step is one exact block_check capture at the doorway pose
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 12:37:55 +02:00
Erik
081a633419 docs(issues): #458 — the block z slab matches retail on both paths; suspects narrowed to the block edge-plane test / view union
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 12:37:05 +02:00
Erik
b1eaab50d9 docs(issues): #458 — not the degrade level; three divergences at the doorway (one far block, two pre-existing missing look-in floods)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 12:35:28 +02:00
Erik
38cedde0fb docs(render): ledger — S3 chunk 1 stops after two fix rounds; landed with open items O1–O5 carried; #458 degrade note
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 12:31:12 +02:00
Erik
05ebe2c805 docs(render): ledger — chunk 1 round 1 landed, three poses reproduce exactly; #458 doorway block admission; round 2 next
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 11:50:45 +02:00
Erik
4ec59d727a docs(issues): #457 — two App tests pin Debug-vs-Release IL offsets (pre-existing)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 10:05:57 +02:00
Erik
e102fb363e fix(render) #132: outdoor alpha drains follow retail walk order
Some checks failed
CI / linux-portable (push) Successful in 3m35s
CI / windows-gate (push) Failing after 6m46s
CI / release (push) Has been skipped
Retail draws every cell's objects inside LScape::draw's far-to-near walk
(DrawSortCell @0x005A17C0) and drains the one delayed-alpha list at the
DrawCells boundary AFTER the finished walk (@0x005A4872). Our outdoor
frame drained at the landscape-stage end and then drew punches, interior
shells, cell objects, and ALL dynamics — every one of those opaque
passes overwrote the already-composited flames (the reopened #132
candle class: "the door draws over the candle", creatures at openings).
Depth and barrier A/Bs were no-ops because the eraser is opaque color
painted after the drain.

Two retail-cited ordering corrections, outdoor-node roots only:

1. The stage-boundary drain is skipped and FlushLandscapeAlpha() runs
   after DrawDynamicsLast, where the frame's opaque world depth is
   complete — the one far-to-near list composites over everything,
   exactly like retail's boundary flush relative to its finished walk.
2. Before DrawExitPortalMasks, FlushLandscapeAlphaFartherThan(
   ExitPortalMaskBarrierDistance(...)) drains everything at or beyond
   the nearest cell whose exit-portal mask is about to write far-Z —
   retail DrawBuilding @0x0059F2A0 runs FlushAlphaList(0f) BEFORE its
   portal-only pass, so in the far-to-near walk nothing already drained
   can meet a punched aperture's falsified depth. Without this, the
   first correction let exterior waterfalls z-pass across punched
   apertures whose true landscape depth the punch erased (found live at
   the cathedral gate). Nearer content stays queued and legitimately
   composites in front of punched structures.

Interior roots keep the pre-clear stage-boundary drain unchanged.

User-gated live: Holtburg sign candle whole in front of the sign and
tower door at the aligned pose; cathedral waterfalls contained at every
camera zoom, inside and outside. Register row AP-236 retired (the
walk-order outcome reconstruction is complete; AP-34 remains the
umbrella for the CYpt-sort reconstruction itself). Filed #456 for the
separate occluded-distant-building/creature admission residual this
session diagnosed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 19:03:35 +02:00
Erik
8acb544d44 docs: file #454 barred timered quest-item icon, #455 paperdoll click-dequip
Both owner-reported 2026-08-29 after the #443 fix gate. #454: a boss
quest item with a reuse timer lands in the backpack with the barred
(unusable) icon overlay and stays barred; expected clear immediately,
timer text is chat-only. #455: clicking an equipped item on the
paperdoll does nothing; the retail gesture and gmPaperDollUI click
handling must come from the named decomp before implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:11:41 +02:00
Erik
cd1cdee0e5 fix(render) #443: private viewports take the ring transform path
The paperdoll was visible only in portal space. Root cause: the classic
WbDrawDispatcher.Draw path appended its transforms into the SHARED world
transform frame (WorldTransformFrameArena.Append) with a non-zero base
instance, but the default mesh shaders index every parallel per-instance
array - clip slots, light sets, indoor, OPACITY, selection lighting,
detail category - zero-based; only the packed world submission's shader
convention subtracts the shared-arena prefix. With a world frame active
the doll drew all instances at per-instance opacity 0 into a cleared
target: counted draws, blank pixels, deterministic. Portal space worked
because no world transform frame is active there, so the same code took
the ring path with base 0. The private viewports are the only production
consumers of the classic path, hiding the defect everywhere else.

Fix: WbDrawDispatcher.NextClassicDrawIsPrivatePass - the private
viewport renderer marks its draw and WriteWorldTransformSection routes
private passes onto the plain ring path unconditionally (self-contained
render state: the private pass owns its own camera, lighting, and
target, and must not depend on the world frame's pose address space).

Also landed, each independently justified:
- Per-GPU-flight-slot private targets (PrivateViewportFlightTargets),
  restoring the pre-f6fe0f2a design: that revert's claim that frame
  submission order protects the single target's write->sample transition
  is not guaranteed across Vulkan command buffers. Per-slot completed
  scenes fix the cleared-sibling-after-reveal wart the old attempt had.
- Paperdoll resource preparation moved to the frame resource phase
  (IPrivateEntityViewportResourcePreparation) before world draws consume
  the bounded composite-upload budget.
- The presenter redresses on every dirty edge (an appearance-equal clone
  can pin retired readiness across generations; the renderer's two-phase
  promote keeps the last completed image visible during replacement),
  publishes only non-zero handles, and clears the viewport exactly once
  at the explicit character-session boundary.

Verified live on the clean build: doll visible in the NORMAL world,
visible through portal space, and still visible after arrival - the
exact reported repro cycle. 26 paperdoll/private-viewport/preparation
tests plus 60 renderer-suite tests pass; owner visual gate pending.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 16:51:32 +02:00
Erik
f7aa8e0eb7 fix: complete retail parity stability pass
All checks were successful
CI / linux-portable (push) Successful in 3m41s
CI / windows-gate (push) Successful in 6m49s
CI / release (push) Successful in 3m22s
2026-08-28 20:01:39 +02:00
Erik
c4608b1127 Merge origin/main into MossTank automation work
Some checks failed
CI / linux-portable (push) Successful in 3m51s
CI / windows-gate (push) Failing after 7m8s
CI / release (push) Has been skipped
# Conflicts:
#	docs/ISSUES.md
2026-08-27 19:01:26 +02:00
Erik
4e6e9bc9d9 feat(mosstank): add VTank-style automation PoC 2026-08-27 18:57:21 +02:00
Erik
1d2f2f738f fix #451: stabilize portal seam rendering
All checks were successful
CI / linux-portable (push) Successful in 3m32s
CI / windows-gate (push) Successful in 6m55s
CI / release (push) Successful in 2m12s
2026-08-27 14:30:21 +02:00
Erik
f6fe0f2a4f fix(client): restore retail interaction parity
All checks were successful
CI / linux-portable (push) Successful in 3m27s
CI / windows-gate (push) Successful in 6m42s
CI / release (push) Successful in 2m12s
Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
2026-08-26 20:45:11 +02:00
Erik
f160f3fee1 fix(ui): wait for private viewport mesh residency 2026-08-25 19:16:53 +02:00
Erik
82e4b4cb6d fix(render): harden portal exit handoff
Some checks failed
CI / linux-portable (push) Successful in 3m19s
CI / windows-gate (push) Failing after 6m43s
CI / release (push) Has been skipped
2026-08-25 17:39:44 +02:00
Erik
ddbd7e4096 docs+fix(ui): Campaign AS CLOSED — connected gate PASSED; AS-GF1 probes stripped; #443 narrowed
Some checks failed
CI / linux-portable (push) Failing after 3m15s
CI / windows-gate (push) Failing after 6m54s
CI / release (push) Has been skipped
The owner ran the Campaign AS connected gate live and passed it. The two
gate findings resolved in-round: the extras-list "black rectangle" is
retail's own authored scroll-less clipped listbox (no scrollbar authored
on 0x10000335, verified against the live DAT; wheel-scroll/resize reveal
rows — AS-GF1 65f6f584 ruled it not a code defect), and the paperdoll
symptom narrowed from "renders nothing" to an intermittent FIRST-OPEN
DELAY: the probe round proved the private render layer healthy from the
first frames (nonzero handle, 34 MeshRefs, sane bounds/camera) for both
the examination clone and the inventory doll, with mesh residency/upload
latency the leading suspect. #443 stays open with that narrowed shape.

Per the probe-dies-with-its-investigation rule this strips
CreatureAppraisalViewportDiagnostics, its call sites, and the
launch-options row in one commit (recoverable via git show 65f6f584).
App hermetic suite green (6,337/0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 14:15:26 +02:00
Erik
65f6f5848a fix(ui): Campaign AS gate fixes AS-GF1 — extras-list overflow ruled OUT as a code defect; paperdoll regression not isolated, probe added instead
Two owner-reported defects at the Campaign AS connected gate on the
examination window (player targets): the animated paperdoll no longer
renders at all, and a "reserved black rectangle" appears at the window's
bottom with the character extras list clipped mid-row at default (310x400)
window size.

ROOT CAUSE — extras-list overflow (the "clipped mid-row" half of defect 2):
NOT a code bug. AS3 (armor-level trio) and AS4 (society/allegiance/
configurable extras) grew the extras list past its DAT-authored 87px region
(element 0x10000335) at the window's minimum size — a new hermetic
regression test proves the worst-case combination (every AS3+AS4 addition
at once) reaches 20 rows / 400px of content, a 4.6x overflow. But retail's
own LayoutDesc authors NO scrollbar for this listbox either
(ScrollbarElementId == 0, verified against both the committed fixture and a
fresh tools/LayoutDump read of the live installed DAT — no drift), and the
SAME test proves UiItemList's pre-existing, unmodified wheel-scroll handler
(OnEvent's UiEventType.Scroll branch) already reveals every row on the next
paint. A scrollbar-less, wheel-scrollable list clipped to its authored
region until the user scrolls or resizes IS retail's own already-correctly-
ported mechanism, not a regression — so no fix was made here.

ROOT CAUSE — paperdoll / "black rectangle" (defect 1): NOT ISOLATED despite
exhaustive investigation. Every file the Campaign AS diff touches
(AppraisalUiController.cs, RetailUiRuntime.cs, CreatureAppraisalRows.cs,
AllegianceRankTitleTable.cs, CharacterIdentityText.cs,
CharacterSheetProvider.cs, InteractionRetainedUiComposition.cs, plus two
unrelated mechanical PublicWeenieFlags-literal refactors) was reviewed in
full against the pre-Campaign-AS baseline. The same worst-case regression
test proves Apply/ApplyCreature/RebuildCreatureStats/BuildExtra never throw
and always leave ActiveView == Character, CurrentObjectId != 0, and the
viewport's full ancestor-visibility chain Visible == true — ruling out
RetailCreatureAppraisalFrameView.TryGetVisibleTarget's first three gates.
CreatureAppraisalPresentation.cs and LivePresentationComposition.cs (the
entire render-time viewport pipeline) are byte-for-byte unchanged across
the whole 974fe88a..87e98395 window. UiViewport.OnDraw draws NOTHING (not
black) when its TextureSlot is unassigned, and the creaturePanel's own
full-panel backdrop (0x10000141) is what would show through instead — the
most likely explanation tying both defects to ONE underlying condition, but
its exact trigger (TryGetVisibleTarget's CurrentObjectId check, or
TrySynchronize's live-entity/mesh-availability check) lies in code nothing
in Campaign AS touches, and could not be reproduced hermetically (needs a
live entity + a live examine exchange).

Filed #443 with the full investigation trail. Added a temporary,
state-change-gated diagnostic probe (ACDREAM_PROBE_CREATURE_APPRAISAL_
VIEWPORT=1, CreatureAppraisalViewportDiagnostics) at both
TryGetVisibleTarget and TrySynchronize so the next live repro pinpoints the
exact failing reason instead of another guess. Per CLAUDE.md's "no
workarounds without explicit approval" and the investigation mode's own
escape hatch ("if you cannot root-cause, say what runtime evidence you
need instead of shipping a guess"), no behavioral fix was shipped for
defect 1.

Tests: AcDream.App.Tests hermetic filter 6,337/0; full-solution hermetic
suite 15,612/0 (all 14 projects green, including the known #442 flake,
which did not trip this run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:58:29 +02:00
Erik
bf8f5b70a9 docs(AS): AS4 fix round — oracle corrections (D1), gate carry-note (D2), record fixes (D3); file #442
The AS4 dual-lens review approved the port as exact and required a
docs-only fix round:

- Ground truth §2b row 1: the Society gate is PRESENCE of Int 281
  (AppraisalProfile::InqInt @0x005B3830 returns found/not-found), not
  value!=0; the color rule is same-bit-first (@0x004b49fd/@0x004b4a49/
  @0x004b4a8b) so a multi-bit local player still resolves green on a
  match; the ??? arm precedes the Radiant Blood test.
- Ruling R5 corrected: the row model carries CreatureAppraisalValueStyle
  but ResolveColor is a deliberate no-op until AP-110's FontInfo-list
  residual lands — the Society green/red is model-only and invisible at
  the connected gate; AS6's script must not gate on row colors.
- Ledger: AS4 land 4ade9b04; true full-solution hermetic count is 15,528
  (the AS4 commit body's 15,410 was a mis-report; the review re-ran and
  reconciled 15,483 + 45 new = 15,528).
- #442 filed: pre-existing parallel-load flake in the shadow-caster
  zero-allocation pin, surfaced by the review's full-solution run;
  isolation evidence recorded; unrelated to Campaign AS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 09:58:47 +02:00
Erik
9ffc869925 docs: Campaign CT gate PASSED; file #441 (death/lifestone return, intermittent); retire the CT-era hover probe
The ACDREAM_PROBE_UI_HOVER probe dies with its closed investigation
(scrollbar hover, fixed 2d6333f8) per the launch-options rule; #441
stays filed with its probe recipe for the next occurrence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 07:44:42 +02:00
Erik
d087b50aa3 fix(ui): tooltip wrap bound comes from the popup text child's authored P0x3D, and tooltip text left-aligns
All checks were successful
CI / linux-portable (push) Successful in 3m29s
CI / windows-gate (push) Successful in 6m14s
CI / release (push) Successful in 2m10s
Owner screenshots vs retail at the CA5 re-check caught both:

Wrap width: the popup skins' shared TEXT CHILD (0x10000396) authors
P0x3D=256 on all four skins — live-DAT probed, now pinned by an
installed-DAT test. Retail's InqSizewMargins UITS_MAX_WIDTH reads the
text element's 0x3D BEFORE the display-width fallback, so retail wraps
tooltip text at 256px; our measure pass used the display width because
TS-85's 'zero elements author P0x3D' sweep had only covered hover
TARGETS, never the popup skins. ApplyTooltipText now measures and
re-wraps at the text child's authored bound, falling back to the display
width only when none is authored.

Alignment: tooltip text rendered centered where retail hugs the left
edge. The skin authors no justification; retail's unauthored default is
Left, our importer's ElementInfo default is Center — the same
wrong-default class as #410's VJustify finding, now recorded there as the
horizontal sibling. Point-fixed in the presenter exactly as the chat
transcript already does; the client-wide default flip stays #410's scope.

The two-pass sizing test now models the real skin (max width on the text
child) and asserts left alignment. Full hermetic suite 15,332 passed / 0
failed; the new live-DAT pin passes against the installed DATs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 18:29:03 +02:00
Erik
bce17b3cfb fix #430 #440: character panel — tooltips can mount, and rows refresh on the authoritative record
Some checks failed
CI / linux-portable (push) Failing after 3m25s
CI / windows-gate (push) Successful in 6m12s
CI / release (push) Has been skipped
Two defects the owner found at the CA5 drive, one shared theme: the data
was right and the presentation seam was dead.

#430 (tooltips): the TS-85 Batch-B port set runtime TooltipText on the
runtime-built attribute/vital/skill rows but never gave them a popup
locator, and RetailTooltipPresenter.OnTooltipShow refuses any widget with
AuthoredTooltipRootElementId == 0 — the tooltip could never mount, on any
row, ever. (The register's 'live-verified on the Character tab' was the
OPTIONS panel's Character tab — authored elements with authored locators;
a different surface.) Rows now carry the shared popup skin
0x10000395/0x21000041 — live-DAT probed as the ONLY locator pair the
character layout references, and the same inference UiItemSlot already
ships for runtime-built widgets. TS-85's row carries the dated correction.

#440 (train row stuck): training a skill debited credits on screen but
left the row in the untrained section until the NEXT click — because the
sheet-changed subscription only refreshed the captured sheet, and row
STRUCTURE rebuilt exclusively in click handlers (the raise 'completed'
callback runs after SEND, before the server answers; the owner's second
click was simply the first rebuild after the record landed, and ACE's
rejection of that second train — 'Failed to train', no credit change —
matches the owner's report exactly). The same gap kept CA4's
awaiting-ghost from visually releasing. CharacterStatController.Bind now
returns the data-changed refresh and MountCharacter invokes it on every
authoritative sheet change, mirroring retail's quality-change broadcast
(InfoRegion::OnQualityChanged @ 0x004F0EB0).

Pinned by DataChangedRefresh_MovesATrainedSkillToItsSection_WithoutAClick
and Rows_CarryTheSharedTooltipPopupLocatorAndDescriptionText. Owner
visual re-check owed next session (hover-dwell a row; train a skill and
watch it move immediately). Full hermetic suite 15,329 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 16:51:58 +02:00
Erik
65430d4c7c feat(net) Campaign CA CA2 #431: parse the inbound attribute/skill update family
Some checks failed
CI / linux-portable (push) Successful in 3m32s
CI / windows-gate (push) Successful in 6m22s
CI / release (push) Has been cancelled
The server's authoritative answers to a raise were dropped on the floor:
only the vitals pair (0x02E7/0x02E9) had parsers, so after any
RaiseAttribute/RaiseSkill/TrainSkill the client's stat model stayed
frozen at login's PlayerDescription — the root cause of #431's stale
derived skills and run speed. The GUI looked alive only because the
panel applies optimistic local raises.

New parsers with three-source-verified layouts (CA1 research doc §2.5/
§2.8): PrivateUpdateAttribute (0x02E3) and PrivateUpdateSkill (0x02DD —
the wire's ushort ranks + hardcoded adjustPP=1 pair and f64
lastUsedTime preserved exactly). WorldSession dispatches both as typed
events; LiveSessionEventRouter routes them into the J4 character owner's
LocalPlayerState like every other private update. The vestigial
PrivateUpdateSkillLevel (0x02DF) is deliberately unparsed — ACE has no
producer (verified).

OnAttributeUpdate now fans out to the derived-value observers, mirroring
retail's live-at-inquiry model (CACQualities::InqSkill 0x00592660 —
Set* writes raw, Inq* recomputes, notification carries no value): an
Endurance write notifies the Health AND Stamina vital observers (ACE
pushes only a Health record and its own comment says the client must
refresh both), Self notifies Mana, and every attribute write notifies
character-sheet consumers whose formula contributions just changed.
OnSkillWireUpdate preserves the login FormulaBonus — the wire record
carries no attribute contribution; CA3 replaces the cached field with
the live computation.

Also corrected while in the neighborhood: PropertyString.cs's comment
claimed opcode 0x02DD for PrivateUpdatePropertyString; ACE's enum says
0x02D5/0x02D6 (doc-only — nothing dispatched on either).

Conformance tests cover both layouts (including holtburger's golden
skill fixture with adjustPP=1), truncation/wrong-opcode rejection, the
Endurance/Self/Quickness fan-out contract, and FormulaBonus
preservation. Full hermetic suite 15,333 passed / 0 failed (one
load-sensitive transport flake observed on the first run, passed alone
and on the clean re-run — filed as #439 rather than chased).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 13:38:50 +02:00
Erik
20721ddada docs: open Campaign CA — character advancement retail parity (promotes #431)
The owner widened #431 into the full advancement family: real-time
refresh of vitals maxima (attribute AND direct vital raises), derived
skills, run speed under Quickness, attribute-less skills like Salvaging,
and the untested train/specialize/respec flows. The promotion survey
pinned the root cause: every outbound raise action (0x0044-0x0047) is
wired — which is why the GUI 'works' — while the inbound private
attribute/skill update family is parsed nowhere (only the vitals pair
0x02E7/0x02E9 is), so the server's post-raise truth never reaches
LocalPlayerState and no recompute ever triggers. Plan doc carries the
oracle targets (message family from ACE/Chorizite/holtburger, retail's
recompute chain in named-retail, specialization/respec semantics) and
five slices ending in a user-driven connected gate. #430 tooltips are
explicitly sequenced after, on the #409 tooltip system.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 13:13:20 +02:00
Erik
373d003f1b docs: file #438 — launcher crash-report bundles (upcoming work); flip #435's stale PARTLY CLOSED header
#438 records the design agreed with the owner: launcher-owned opt-in WER
LocalDumps key (HKCU, minidump, capped count), crash bundle assembled on
the next launch from the dump + log tail + version + capability report,
and an explicit NO-auto-upload line — dumps can hold the plaintext
session password, so sharing stays a user action until there is real
infrastructure and a consent flow. The owner's own machine is already
armed manually for the #422 hunt; this productizes it for alpha users.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 13:06:17 +02:00
Erik
35454a9f58 fix #436: combat no-target refusal reaches the SpewBox with retail's exact text
Attacking with no valid target has told the player nothing since Campaign V
slice V11 orphaned the DebugVM toast the message was wired to (#434 found
the drop; this closes it retail-faithfully).

Ground truth from the Ghidra decompile of
ClientCombatSystem::ExecuteAttack (0x0056bb70): retail writes
"You must select a valid combat target before attacking" via
ClientSystem::AddTextToScroll(..., 0x1A, true, 0) — the ClientLocal
SpewBox channel this codebase already routes every other client-local
refusal through. And retail has ONE message, not the two we carried:
attacking outside melee/missile modes is silent (ExecuteAttack is
unreachable there), so the invented "Enter melee or missile combat first"
text is deleted rather than rerouted, and the invented "No monster
target" is replaced by the retail string, which joins ClientTextRefusals
with its decomp citation.

Wiring: CombatFeedbackSlot gains the sibling BindOwned session-lifetime
shape, and SessionPlayerComposition.CompleteSessionPlayer binds it to
RuntimeCommunicationState.AddText(ClientLocal) with session-owned
teardown — a torn-down session's slot returns to its silent unbound
state. A binding-seam test
(CompleteSessionPlayerBindsCombatFeedbackToTheClientLocalSpewBoxRoute)
inspects the compiled composition for the BindOwned call and its
AddText-routing lambda, so the slot can never again pass its unit tests
while production leaves it unbound — the exact failure mode that hid
this defect. The two tests that pinned the invented strings now pin the
retail contract (exact string; silence for the unsupported-mode case).

Full hermetic suite 15,325 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 12:53:11 +02:00
Erik
c1e6e3da44 fix #435 (part 2, closes it): attribute the unowned probes — delete 7, reclassify 8, restore 1
Part 1 deleted probes whose owning issues were closed. These 14 named no
issue at all, so each was traced to its introducing commit
(git log -S) instead of guessed at. Attribution split them three ways:

DELETED (7, investigations closed): ACDREAM_A8_DUMP_PV and
ACDREAM_DUMP_LIVE_SPAWNS (Phase A8), ACDREAM_DUMP_CLOTHING (#37),
ACDREAM_DUMP_EDGE_SLIDE (#32), ACDREAM_DUMP_STEPUP (L.2.3d-f),
ACDREAM_DUMP_VENDOR (the vendor campaign, 25 call sites across 8 files),
ACDREAM_DUMP_VITALS (#5, four independent read sites). VendorDiagnostics.cs
went entirely.

RECLASSIFIED (8, tools misfiled as probes): the DUMP_CELLS/DUMP_GFXOBJS
fixture-extraction family (replay-harness tooling with a roundtrip test),
PROBE_CELL (standing cell-transit tracer, pair of the permanent
PROBE_RESOLVE), DUMP_SKY and HIDE_PART (generic isolation tools), and
DUMP_STEEP_ROOF — which looked like an L.4 relic but observes LIVE
divergence-register row AD-56; deleting it would have removed the only
runtime lens on an active divergence. All moved to Permanent diagnostics
with their attribution recorded.

RESTORED (1): ACDREAM_DUMP_MOVE_TRUTH was deleted and un-deleted the same
day. It is not a probe — the canonical nine-stop soak
(run-connected-r6-soak.ps1) hard-fails every destination without its
'move-truth OUT' records, with a message that would misdirect the next
operator. Under the no-workarounds rule the gate's mechanism is restored,
not left broken with an IOU (#437, closed). Process lesson recorded on
both issues: a closed owning issue is NOT sufficient to delete a probe —
grep tools/ and the contract tests for consumers first.

Also lands the owner-requested default-off invariant: every diagnostic in
the codebase is inert until its env var is explicitly set. Exactly four
flags default ON and none is a diagnostic — RETAIL_CHASE, CAMERA_COLLIDE,
CAMERA_ALIGN_SLOPE, RETAIL_CLOSE_DEGRADES are retail behaviors wearing an
A/B off-switch. That set is now FROZEN by
LaunchOptionsDocumentationTests.OnlyTheFourRetailBehaviorFlagsDefaultOn;
docs/launch-options.md's Conventions and CLAUDE.md state the rule, and
CLAUDE.md now binds future probes to a documented row in the same commit.

The client reads 137 environment variables (161 at audit start); 40
temporary probes remain, every one attributed. Full hermetic suite 15,322
passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 12:32:42 +02:00
Erik
0c5057c9ff fix #435 (part 1): delete 17 probes that outlived their closed investigations
Each of these was temporary apparatus added to chase one bug, and each was
supposed to be deleted in the commit that fixed it. Fourteen closed issues
later they were still here: #337's support/wire-mesh trio, #171's sticky
timeline, #119's viewer and entity dumps, #113's phantom probe, and a dozen
more. 3,493 lines removed; the client now reads 144 environment variables
instead of 161, and 47 temporary probes remain instead of 64.

This is not only tidying. Every probe leaves a branch on its hot path when
unset, several re-read the environment per call rather than caching, and
the volume buries the diagnostics that are actually load-bearing. It is
also a headless correctness matter: HeadlessStaticStateAudit reflects over
PhysicsDiagnostics' flags to refuse a multi-session host when any is set,
and cannot see probes that live outside that owner.

Four files went entirely — WalkMissDiagnostic.cs, CollisionMeshWireframe.cs
and two test files whose only subject was a deleted probe.
TransitionTypes.SetContactPlane also sheds its CallerMemberName /
CallerLineNumber parameters, which existed solely for #337's cpSrc=
attribution and carried the instruction to strip them with the probe
family; no call site passed them, so no behavior changes. F2's collision
overlay survives and reverts to its proxy-cylinder form, which is what
removing the ACDREAM_WIRE_MESH upgrade means.

LaunchOptionsDocumentationTests earned its keep here: it refused the
deletion until docs/launch-options.md moved the 17 rows into Retired and
the frozen direct-read counts came down (PhysicsEngine.cs to zero,
TransitionTypes.cs 3 to 2). The documentation could not drift during a
cleanup this wide.

The 14 probes that name no owning issue are deliberately NOT deleted.
Nothing records when they became safe to remove, and guessing is how a
future investigation loses apparatus it needed; #435 stays open for their
attribution.

Full hermetic suite 15,321 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 11:41:20 +02:00
Erik
05bfe8d162 fix #434: delete the unreachable DebugPanel/DebugVM surface and the comments that advertised it
DebugPanel and DebugVM have not been constructible since Campaign V slice
V11 removed the ImGui frontend that hosted them: nothing in src/ ever
called their constructors, only a test did. Two consequences, both fixed
here — 35 environment reads inside them were unreachable, and roughly forty
XML doc comments across the diagnostics owners promised a runtime checkbox
that no longer exists. A flag documented as runtime-toggleable when it is
startup-only sends the next investigation down a path that cannot work.

Deleted DebugPanel.cs (340 lines), DebugVM.cs (548) and DebugVMTests.cs
(327). Corrected the surviving claims in PhysicsDiagnostics,
RenderingDiagnostics, CameraDiagnostics, PhysicsEngine and GameWindow to say
what is actually true: these flags are set from the environment at startup
or by direct assignment.

The one real dependant was CombatFeedbackSlot, whose binding target was
DebugVM. It now takes a plain Action<string>, which removes the dependency
without changing behavior — and makes visible that there is no behavior:
nothing binds the slot, so the combat refusals it carries ("No monster
target", "Enter melee or missile combat first") have been discarded all
along. Filed as #436 and pinned by a test, rather than papered over with an
invented chat message; the retail text and channel need the oracle first.

Deliberately untouched: F1's AcdreamToggleDebugPanel binding, which
GameplayInputCommandController consumes as a documented no-op so the key
does not fall through to a lower input scope; and the
DebugVmRenderFactsPublisher / DevToolsRuntimeSources chain, which is still
wired into production composition and deserves its own dead-code pass
instead of being pulled into this one.

Full hermetic suite 15,333 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 10:58:59 +02:00
Erik
e77dd7c413 docs: launch-options reference + the test that keeps it honest
The client reads 161 ACDREAM_* environment variables across 79 files. Only
about 25 were written down, and the audit found the documentation drifting
in both directions: CLAUDE.md still advertised ACDREAM_RUN_SKILL /
ACDREAM_JUMP_SKILL (deleted; skills are server-authoritative now, and the
jump fallback is 300, not the documented 200), while flags with real
side effects had no description at all.

docs/launch-options.md documents every one by lifecycle — production,
command line, measurement, automation, permanent diagnostics, temporary
probes, deprecated, retired — with a mandatory side-effects column. That
column is the point: #432 cost three days of taxed measurements because
ACDREAM_AUTOMATION_ARTIFACT_DIR reads like an output path and also builds
a per-frame diagnostics referee, and ACDREAM_STREAM_RADIUS silently
measures a streaming window production never uses. Rows now say so. Other
surprises the audit surfaced and recorded: ACDREAM_DUMP_SCENERY_Z swaps in
a duplicate scenery-placement path rather than only logging,
ACDREAM_PROBE_VIS silently also enables ACDREAM_PROBE_ENVCELL, and
ACDREAM_DUMP_ENTITY's id list doubles as an unrelated probe's watchlist.

LaunchOptionsDocumentationTests enforces it, because a hand-maintained list
of 161 flags is stale within a week: an undocumented flag fails, and so
does a documented row whose read site was deleted. It scans string literals
rather than GetEnvironmentVariable call shapes — the startup path reads
through an injected delegate, so a call-shaped pattern silently missed
ACDREAM_LIVE, ACDREAM_PAK_PATH and every other production flag. A third
test freezes per-file direct-read debt by exact count (20 files outside the
owner classes), so structure rules 4 and 5 can be paid down but not
regressed.

CLAUDE.md's 94-line env-var section becomes a 16-line pointer, and its
stale test-character paragraph is corrected.

Also fixed, all doc-vs-code mismatches the audit proved:
- RenderingDiagnostics.FrameProfEnabled described a GPU-query self-disable
  that Campaign V slice V11 deleted.
- Two comments named ACDREAM_RENDER_BACKEND as a live co-requisite; it died
  with the OpenGL backend.
- EnvCellRenderer.CollectCellAuditLines and its ACDREAM_A8_AUDIT doc: the
  method had no caller anywhere and its documented caller never existed.

Filed rather than fixed, to keep this a documentation change: #434 (the
DebugPanel/DebugVM surface is never constructed, so ~40 "runtime-toggleable"
comments are false and 35 env reads are unreachable) and #435 (17 temporary
probes outlived their closed investigations; 14 more name no owner).

Full hermetic suite 12,202 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 10:28:59 +02:00