Commit Graph

3 Commits

Author SHA1 Message Date
d5cfcbdc9c fix(权限): 409 的第二种含义是「本档不该问」——四桥都补上;状态写入点不再兜默认档
线上事故(jianf 经 pi 转达):补投路径漏传 permission_mode,插件拿 undefined 兜了
workspace 档,把 full 档会话写成 workspace-write + ask —— 不是"拦一次",是一整轮
工具能力降级,且状态留在会话里;随后该会话每次受守卫调用都撞 409。

四件事:

1. **状态写入点不接受默认值**(新增共享 `modeForStateWrite`):缺字段/脏值 → `null`
   = 不写状态。"默认值可以出现在**决策**里,不可以出现在**状态写入**里。"
   同时保留共享契约的 fail-closed:真读到 workspace 才写 workspace。

2. **409 的两种含义分开处理**。`allowed-once` 只绕过**审批**,改不了**沙箱** ——
   所以 dsh 桥在放行前先把服务端给的权威档位**写回会话**(这也就成了自愈路径:
   已经降级的会话,下一次带档位的 409 会把它修回来);只认服务端明说的 full,
   plan 与"链上没有人类"照旧 fail closed。

3. **同一处缺陷在 zcode / opencode 也在**(`hooks/permission.mjs` 与 `index.js`
   都把 409 当永久失败拒绝)。我先前在回信里写过"这两个桥不转发权限询问,不需要改"
   —— 那句话是错的,我当时的搜索面只有 `<plugin>/src/*.mjs`。按 pi 的要求把这条
   **否定性事实变成常驻判据**后,它第一次运行就红给我看。四桥现在都有
   「409 + full → 放行」,且**排在永久失败分支之前**(含顺序变异自检)。

4. **共用测试重新同源**:`test/catchup.test.mjs` 从 `153985e` 起就是分叉的
   (我那版把平台专属路径写进了共用文件),而 `deploy/install.sh` 第 24 行会跑
   `check-shared-libs.sh` —— 也就是说**部署一直是红的**,我没跑过那个脚本。
   共用文件只放契约(值/行为),跨平台配对judge 移到平台专属文件,四份逐字节相同。

另外把"判代码 vs 判理由"从记忆变成代码:`test/lib/read.mjs` 提供 `code()/prose()/bytes()`,
判据目录里不得再裸用 `readFileSync`(新判据 `criteria-hygiene` 管,含读取器自检)。

判据证据(每条都做过"能不能红"的变异):
- 写回去掉 → 红;纠正块挪到普通 409 之后 → 红;状态写入点退回兜默认 → 红;
- zcode/opencode 的放行分支拿掉 → 各自红;共用测试分叉 → check-shared-libs 红。

各套件:dsh 388、pi 443、zcode 387、opencode 333(均经 npm test,含 tsc);
electron `npm test` 15/15 判据绿 + vitest 266 + typecheck;`check-shared-libs.sh` 退出 0;
Go `go test ./...` 全 ok。
2026-09-14 16:21:27 +08:00
f6feb7c0df test(webui): 「滑动硬截断」诊断脚本(自带浏览器,不依赖共享实例)
用户:「webui 大片界面存在滑动硬截断」。

## 现状:这一轮我**没能复现**

量法是"内容溢出但没有可滚动祖先"⇒ 候选 0 个;换成用户视角四问
(有没有可滚动容器 / 能不能滚到底 / 末尾有没有被切 / 页面自己溢不溢出)后:

    390×700  通信  日历  联系人  我的 
    1400×700 通信  日历  联系人  我的 
    (造了 12 个会话、正文都很长;验完已归档)

即按这四种量法都测不到硬截断。**长正文详情页**那一块我的探针超时没跑完 ⇒
**未判定**,不能算"没问题"。

## 这次的交付物

`client/electron/test/manual/scroll-cut-verify.mjs`:把上面这套量法固化下来,
并且**自带浏览器**(不连共享 9222)—— 共享实例被历次被中断的运行留下僵尸上下文后,
`connectOverCDP` 会一直超时(我这个会话里已经遇到三次),诊断脚本必须在
"共享实例状态未知"时也能跑。

## 我需要的(否则只能继续猜)

请指一下**具体页面 + 具体手势/位置**:哪一屏、滚轮还是触摸拖动、硬截断出现在
列表末尾还是详情正文?也可以直接看截图。我上一轮"窄屏显示不全"也是同样情况 ——
我量不出来、但你说有,那多半是我量的维度不对。
2026-09-14 13:43:11 +08:00
76ce201c3a feat(webui): 导航合并 + 悬浮玻璃 + 页面动画 + 控件档透明度 + 圆角无条件生效
用户四封信(同一线索)提的六件事,都在这里:

## ① 导航合并(「导航栏的内容有点多了」)

收件箱/发件箱/授权 → 一项「通信」,进去由**内部页签**区分(CommTabs);
新建 → 「通信」页内**悬浮圆形加号**(ComposeFab);导航只剩 通信/日历/联系人;
管理 → 合进「我的」,管理员在页面**最下面**看得到(非管理员不渲染,不是禁用)。

`viewMode` 仍是原来那三个值(几十处调用点不用改),新增 `commTab` 记住上次用的子页签;
通信项的徽标 = 未读 + 待决策(授权信息不能因为合并而消失)。

## ② 窄屏底部导航:悬浮玻璃(「还是固定底部延伸,没有玻璃效果,也没有悬浮」)

原来是 `border-t bg-chrome-900` 通栏贴底。改成:左右/离底各留 10px、圆角、
深色半透明 + `blur(18px)`、投影,安全区并入下外边距。

## ③ 页面动画(「页面极度缺少动画,所有页面都是直接出现」)

在 `<html>` 上挂一个短命类触发外壳直接子面板的入场动画。**没有用 key 重挂载**:
面板是 flex 链上的一环,套 wrapper 会改掉 flex 传递(窄屏覆盖层最先坏)。
并且尊重 `prefers-reduced-motion`(关了就一点都不动)。

## ④ 控件档透明度(「复选框和地址猜测项…他们才是真正需要拉低透明度的地方」)

新增第三档 `--bg-glass-control`(0.5/0.55):授权多选胶囊、地址建议菜单。
三档递减:正文面 0.88 > 嵌套 0.82 > 控件 0.5。

## ⑤ 打底 vs 透明(上一封「该打底的地方透了、该透的空白处糊了」)

正文面回到 0.88(读得清优先)、空白/页面底透明**且不模糊**、面板模糊降到 10px。

## ⑥ 圆角与玻璃**无条件**生效(「大面积缺失圆角与玻璃效果…都是硬截断」)

根因:`.app-shell` 的留缝/圆角/投影原先全写在 `html[data-bg='on']` 里
⇒ **没开壁纸的账号**看到的是硬边不透明面板。现在几何下沉为无条件基线,
壁纸相关的加强仍叠加在上面。窄屏内容面板同样浮起来。

## 判据

- `test/nav-merge.test.mjs` 8 条(含自检:重构前的写法必须判红)——
  改完跑老套件 254 条**全绿却一条都没测导航结构**,结构改动必须自带判据。
- `test/manual/nav-restructure-verify.mjs`:真浏览器 9 条(导航项数、页签切换真的换内容、
  加号 56×56 且 `elementFromPoint` 命中自己、我的页底部管理入口在退出登录之后、
  控件档 α=0.5 对正文面 α=0.88 的反向对照)。
- `test/manual/narrow-glass-verify.mjs` 6 条:悬浮几何(三边留缝 10px、圆角 14px、
  缝隙处命中的是页面底 ⇒ 真的浮着)、玻璃(α=0.82 + blur18)、触摸高度最小 49px、
  动画真的在跑(静止时 `animationName=none`,切换后 =pane-in)且 reduced-motion 下不动。
- `test/background.test.mjs`:把三条**过时判据**(早前那版"越透越好")按现行契约重写 ——
  旧判据留着只会把我拽回错误方向。30 条全绿。

## 顺带

窄屏探针原先只调视口、**没模拟触屏**,于是 `(hover: hover)` 仍为真,
把「悬停才显形的次要动作」误报成透明 —— 差点去"修"一个本来就对的规则。
已改成 hasTouch + isMobile + DPR 的触屏上下文,且收尾只关自己的 context
(CDP 连的是共享 Chromium,`browser.close()` 会把别人的标签页一起关掉)。
2026-09-14 10:35:05 +08:00