Files
ark-stronghold-protocol/test/ui
sganggs 51e0e60b6e feedback7 stats: a match left right away stays in the history but does not count; bounded storage, corrupt-data handling, the page reworked as 干员调配-style tabs, the settlement re-view without the app store (PR #323 by @2321Robin, owner's decision of 2026-10-08); golden: unchanged
Counting rule (ui/stats.js countsTowardStats, the owner's decision of 2026-10-08: do not count the matches entered and left
right away, but keep them in the history): a settled match (m.result arrived) always counts; a match given up (放弃模拟)
counts once at least one of the player's battles had finished — a round cleared (the server's own rule, platform.js
_quit: leaving while round k runs has passed k - 1, in its settlement k) or already eliminated. Anything earlier is
history only: marked 中途退出 and 不计入统计, dimmed, listed in 对局记录, left out of every aggregate (games, wins, win
rate, strategy table, titles, rounds, time, combat totals); 总览 says how many were left out.
- A leaver gets no m.result, so the page records the match itself: quitMatch (放弃模拟) → recordQuit builds an
  `end: 'quit'` record from the app state and a tracker (observeMatch, installed in main.js) that remembers when the page
  first saw the match and the last round the player was seen alive in. No record for a spectator seat, a match with its
  settlement already there, a match the page never saw; matches the server ended and closed tabs are not recorded.

Defects of PR #323 as submitted, reproduced (scratchpad/w7-stats-notes/repro-pr-bugs.mjs, loads-check*.mjs) and fixed:
- the title screen loaded all 16 game data files (5.3 MB) at boot: <StatsHost/> called useGameData() at mount; now the
  host renders nothing until opened, the overview reads config / bands / assets and the settlement re-view loads the rest
  when opened (the title screen loads the same 3 files as before);
- importing a file put the list oldest first (the page shows the first 20 as the newest and the cap would drop the
  newest); the list is newest first everywhere, also when loaded from storage;
- recordResult wrote over the envelope of a NEWER build (a downgrade, against the PR's own rule); it refuses now, as
  saveStats does;
- 1000 four-player records are ~7.2 M characters (the PR's ~1.5 kB/record is a solo match) against a ~2.5 M-character
  quota: MAX_RECORDS 1000 stays, plus a 800 000-character budget (the oldest go first), and only the newest 30 records
  keep their rows (lineup, bonds, teammates' names; the replay needs them) — older ones are compacted to the player's own
  summary row (~620 characters), a refused write retries with half the history; unknown fields and oversized values are
  dropped (a strict schema), import files are bounded (8 MB);
- the re-view clobbered the app store (match.public / match.result, the route, the music); ResultScreen is split into
  ResultScreen (the store) and ResultView (props: result, myId, back label), so the stats page renders a stored match
  itself; a 自选 pick and a 补位 stand-in were dropped from the stored lineup (the replayed card drew the plain
  operator); DIFFICULTY_NAMES were not translated; a band cell was a display:flex <td>; the overlay stayed open when a
  co-op match started; the 清空 two-step blink was replaced by the shared confirm dialog.
- Corrupt storage: unreadable data is moved to sp.pref.stats.damaged and the page says so; damaged rows are dropped and
  counted; duplicates, an oversized or unsorted list are repaired on load; a pre-`end` (PR-era) envelope reads as settled.

UI: a full-screen overlay in the grammar of 干员调配 (top bar with 返回 / four tabs 总览 · 策略 · 战斗累计 · 对局记录 /
导出 导入 清空, a note line saying the data stays in this browser and that teammates' names are stored too), text sizes
with max(.xxrem, N px) for phones in landscape, a 50-row history page with 显示更多, a pass-rate bar, a per-difficulty
table in order; the entries use a new `chart` icon (not the ping bars), the title screen's sits beside the language menu
(the connection row has no room: it squeezed the gear and wrapped the status text), the lobby / room buttons show the
icon alone below 700 px (the room's title ran under the label at 640 px). docs/PLAYING.md §12, README row; 41 + 25 UI
strings in en / ja / ko / zh-TW (the PR's four unused ones removed).

Tests: test/ui/stats.test.js 44 / 44 (counting rule per phase, quit records, bounds, corrupt / old / newer storage,
import order, aggregation, the replay payload); test/ui/stats.e2e.test.js (opt-in SP_E2E=1, real server, headless Chrome:
seeded history on 1920×1080 and 844×390, the re-view, export / import / clear, corrupt and newer storage, and the real
flows: a solo match given up in the briefing is history only, one given up after round 1 counts, a settled match is
recorded once and not again after a reload) 6 / 6; lint 0 errors, i18n extract 0 / check --all --strict clean,
check:imports, typecheck, docs and version tests, golden unchanged.
2026-10-08 20:36:41 +08:00
..
2026-10-07 11:47:09 +08:00
feedback5 WE: the 整备区 rules of PRTS 卫戍协议/帮助 §手牌区 (GitHub #82, second part) — a full regular hand refuses every purchase and reward pick, also one whose copy would complete a merge at once ("当常规手牌区全满无空位时,玩家将无法执行使手牌溢出的操作" — "例如招募/购入等通常情况下会增加手牌的操作"; BWIKI 盟约 says the same with no exception; the reporter checked it in the official game), and a free regular slot pulls the 临时整备区 in at once ("常规手牌区出现空位时自动移入"): PlayerState._fillHandFromTemp runs in every recompute, the temp row right to left (the order it fills, [ASSUMED]) into the hand's free slots right to left — after a sale, a deployment from the hand, a merge that consumed hand copies, an item equipped / destroyed / used, a summon stack removed with its owner. invariants.js: temp holds pieces only while the hand is full. The client's refusal path follows (gameLogic.shopBlockReason: 整备区已满 on every card — a one-line change in a file the R5 split moves). Bots: a full hand never tries a purchase, an affordable third copy of a held pair sheds the weakest hand single first (never one of this prep), resolveTemp decides temp right to left. Tests: test/match/feedback5-hand.test.js; merge / hardening / playtest6-elite-to-board / economy / prep-bench / uiFixes updated to the rule. Docs: META §1 Hand, DESIGN §6, PLAYING §3, research 00-INDEX / 01 (the old "a merge-completing purchase is allowed" corrected). Golden: 3 match scenarios moved (coop2-NORMAL-3, solo-HARD-9-boosted, coop2-ABYSS-10-boosted — bot seats that reached a full hand: the merge-completing purchase refused or a single shed first, temp pieces moving in by themselves); every battle digest unchanged
2026-10-05 18:17:08 +08:00