refactor+docs(W27): 删掉只被测试养着的 AdminAccess.availablePages,让 ChatImageBudget 的公式只留一处,并就地更正 devdocs/03 四处过时表述

清理(零行为变化)
- 删 domain/admin/AdminAccess.kt 的 availablePages():全仓(含 app/src/test)调用点 0 处 ——
  main 里只有它自己的声明、测试里 2 处(AdminAccessTest 那 1 条用例一并删掉)。它早已被
  ui/admin/AdminHomeScreen.kt 的做法取代:遍历 AdminPage.entries + 每行 canAccess 决定是否禁用。
- ChatImageBudget.SERVER_MAX_CHARS 原来把 base64Chars 的 ((n+2)/3)*4 又内联重写了一遍,
  改为 base64Chars(SERVER_MAX_DECODED_BYTES) + PREFIX_ALLOWANCE_CHARS(一处公式、一处真相)。
  代价:该常量由 const val 变 val(const 不允许调用函数)。取值逐位不变 = 6990572,由
  ChatSendPolicyTest 的独立重算断言与 ChatDtoRealPayloadTest 对服务端真实文案的断言继续钉住。

文档(devdocs/03,一律删除线保留原文 + 更正括注,不动别人的回执段落)
- §4 重连补全:02/A5 的 after 正向增量已接入(loadAfter + ChatViewModel.catchUp,28c3142)。
- §4 忙碌/队列 UI 映射:客户端只发 scope:"current",该档 dropped 恒为 0、all 从不发,
  所以「已打断,丢弃 N 条」在今天的客户端里不可达。
- §5 mode 回落:mode 已落库(后端 b686d5f),MessageBubble 按 mode 分支。
- §4 打断模式:补上 W25 接线的依据 cfdc094 / feat/W25-interrupt-scope。

devdocs/05 追加 W27 小节;另记下 data/ws/WsEvent.kt:272 的同类过时 KDoc(不在本轮允许改动的
文件清单里,未动)。

验证:assembleDebug 通过;testDebugUnitTest 891 条 / 0 失败 / 0 错误(改动前 892,删掉 1 条)。
This commit is contained in:
AskaEth committed 2026-10-04 22:35:20 +08:00
1 parent e4c6c7c72a
commit 805d8b530a
5 files changed
+49 -21

No files matched your search

@@ -89,6 +89,3 @@ fun canReceiveObservabilityFrames(role: AdminRole): Boolean =
* 而不是散在各处 `if` 里靠人记。
*/
fun canReadObservabilityLogHistory(role: AdminRole): Boolean = canAccess(role, AdminPage.Overview)
/** 当前角色可用的页,顺序与 [AdminPage] 声明一致。 */
fun availablePages(role: AdminRole): List<AdminPage> = AdminPage.entries.filter { canAccess(role, it) }
@@ -29,9 +29,16 @@ object ChatImageBudget {
/** `data:` URI 前缀(`data:image/jpeg;base64,`)的字符余量,与服务端同一取值。 */
const val PREFIX_ALLOWANCE_CHARS = 64
/** 服务端 `image` 字符串长度上限(= base64 膨胀 4/3 + 前缀余量)。 */
const val SERVER_MAX_CHARS =
((SERVER_MAX_DECODED_BYTES + 2) / 3) * 4 + PREFIX_ALLOWANCE_CHARS
/** [byteCount] 字节 base64 编码后的字符数(每 3 字节 → 4 字符,末组补满)。 */
fun base64Chars(byteCount: Int): Int = ((byteCount + 2) / 3) * 4
/**
* 服务端 `image` 字符串长度上限(= [base64Chars] 的 4/3 膨胀 + 前缀余量)。
*
* 刻意复用 [base64Chars] 而不是把公式再内联写一遍:公式只留一处。代价是它只能是 `val`
* ——`const val` 不允许调用函数;取值在对象初始化时算出,与内联写法一致。
*/
val SERVER_MAX_CHARS: Int = base64Chars(SERVER_MAX_DECODED_BYTES) + PREFIX_ALLOWANCE_CHARS
/** 本端目标:重编码后的**字节**上限,远低于服务端硬顶(见类注释)。 */
const val MAX_DECODED_BYTES = 1 * 1024 * 1024
@@ -42,9 +49,6 @@ object ChatImageBudget {
*/
const val MAX_DIMENSION_PX = 1280
/** [byteCount] 字节 base64 编码后的字符数(每 3 字节 → 4 字符,末组补满)。 */
fun base64Chars(byteCount: Int): Int = ((byteCount + 2) / 3) * 4
/** 字符串长度是否在服务端上限内(入口层同一判据:`<=` 才算通过)。 */
fun withinServerLimit(dataUriChars: Int): Boolean = dataUriChars <= SERVER_MAX_CHARS
@@ -53,15 +53,6 @@ class AdminAccessTest {
assertEquals(AdminRole.Viewer, AdminRole.of("viewer"))
}
@Test
fun `available pages follow the declared order`() {
assertEquals(
listOf(AdminPage.Overview, AdminPage.Personas),
availablePages(AdminRole.Viewer),
)
assertEquals(AdminPage.entries.toList(), availablePages(AdminRole.Owner))
}
@Test
fun `monitor tier is weaker than owner admin tier`() {
assertTrue(AdminTier.Monitor.rank < AdminTier.OwnerAdmin.rank)