Conversation
pageLoad 已在生产者一侧过滤无 tab 的页面加载,这里在真正写 tabScript:<tabId> 的 sink 再挡一层:tabId <= 0 直接返回。旧实现在 frameId 为 0 时会先清空列表, 一旦有别的发送路径带来 -1,后台脚本会被整批挤掉。 新增用例: - tabId 为 -1 / 0 时 addScriptRunNumber 不改动 tabScript:-1(撤掉守卫后失败)。 - 契约测试:无标签页的页面加载/iframe、菜单注册注销、普通脚本启停与运行状态事件之后, tabScript:-1 仍只含后台脚本。 Refs #1774 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Collaborator
|
在 #1783 上追加了 e773c1b4:在写缓存的 sink 端补第二道防线,并把 本次提交
|
| Writer | tabId 来源 | 能否新建条目 | 能否写 -1 |
|---|---|---|---|
addScriptRunNumber |
popupPageLoadUpdate 事件 |
能(runNum = 1) |
现在不能(本次守卫) |
installScript / enableScripts 订阅 |
写死 -1 | 能,但先按 DB type 跳过 SCRIPT_TYPE_NORMAL |
只写 -1 |
scriptRunStatus 订阅 |
写死 -1 | 不能,只改已存在条目的 runStatus / runNum(1 或 0),没有 type 检查 |
只写 -1 |
updateRegisterMenuCommand |
调用方,sender.tab?.id || -1(gm_api.ts:1136) |
不能:updateMenuCommand 对不在缓存里的 uuid 直接 continue |
只能给已有条目挂菜单 |
脚本删除清理 / clearData(tab 关闭) |
扫描全部 key / 真实 tabId | 不能,只删 | 只删 |
对计划里几个假设的结论(均为静态分析,没有浏览器实测)
registerMenuCommand路径:排除。 它无法创建条目,只能给已存在的条目加菜单,因此不会产生runNum === 0的普通脚本条目。另外,issue 里的 GreasyFork 脚本(462130)头部只@grant unsafeWindow / GM_getValue / GM_setValue,根本没有GM_registerMenuCommand。runNum === 0的来源:scriptToMenu给普通脚本的初始runNum是 0,但addScriptRunNumber新增条目时会改成 1,所以刚被污染的条目是 1,不是 0。之后能变成 0 的唯一写入者是scriptRunStatus(非 RUNNING 一律置 0,popup.ts:729;弹窗前端usePopupData.ts:185也有同样的置 0)。- 背景列表点「运行」:
RuntimeService.runScript(runtime.ts:1724)没有 type 检查,弹窗只对列表里已有的条目提供「运行」;沙盒执行会先后发 RUNNING / COMPLETE。所以它只能操作已经被污染的条目,不能创建条目;点过一次之后条目会停在runNum = 0,也就是截图里的灰色。这和 PR 描述的「先污染、再手动运行」一致,但没有实测,也不能解释「test 副本为什么不出现」。 - DB
type异常:不太可能经安装/更新产生。type只由 metadata 决定(@crontab→ CRONTAB,@background→ BACKGROUND,否则 NORMAL,src/pkg/utils/script.ts:164-174),更新时类型变化会被error_script_type_mismatch拒绝(同文件:290)。这个 GreasyFork 脚本头部没有这两个标签,新装必然是 NORMAL。导入 / 同步路径没有单独审。 - 「没有真实 tab 的 context 是否该执行 userscript」: 静态看,
getScriptsForTab不使用tabId,行为没有被这个 PR 改变;要不要在getScriptsForTab之前就拒绝这类 context,需要真实 sender 证据,所以没动。
没做的
- 需要真机 / reporter 配合的项(安装来源四组对照、Quetta + Android 15 重现、diagnostic 导出)没有做。
- 临时 debug 日志与开发环境断言(
NORMAL → tabScript:-1warning)没有提交:计划里本来就是临时手段,放进主干会留下常驻噪音。如果 reporter 能装 debug build,可以另出一个只含这个 warning 的构建。 isRealTabId()的集中化留给单独的 cleanup PR。
验证
pnpm run typecheck、改动的两个文件eslint/prettier --check通过。popup.test.ts+runtime.test.ts:114 个用例全过。pnpm exec vitest run --no-coverage src/app/service/service_worker/:649 过,2 失败,都在trash_freeze.test.ts,与 PR 描述里记录的基线不稳定一致;该文件单独跑 2/2 通过。
合并 / 关闭判断
- 🐛 页面不属于任何标签页时不再记入后台脚本列表 #1783 自身:
pageLoad无 tab /tab.id = -1不再发事件 ✅;正常 tab 行为不变 ✅;addScriptRunNumber拒绝tabId <= 0✅;tabScript:-1回归与契约测试 ✅;CI 以页面上的结果为准(我没有等)。 - [BUG] 非后台脚本却显示在“开启和运行的后台脚本”里 #1774:仍缺少「谁第一次把普通脚本放进
tabScript:-1」的直接证据,也没能解释 test 副本不出现,所以保持Refs #1774。
- 契约测试:session 缓存读取不拷贝,expected 直接持有缓存引用时,被测路径原地修改 (如 menu.push、runNum 赋值)会连 expected 一起改掉,toEqual 恒真。改用 structuredClone 快照;在 scriptRunStatus 订阅里临时注入原地改 runNum,旧断言通过、 新断言失败,已验证后还原。 - addScriptRunNumber 守卫由 tabId <= 0 改为 !(tabId > 0),undefined / NaN 这类越过类型 的运行时数据同样拒绝,并补对应用例(守卫收紧前失败)。 Refs #1774 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Collaborator
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist / 检查清单
N/A — 第一项:修复针对的是维护者判定的成因,#1774 报告者的实际场景尚未实机复现,所以没有用关闭关键词,是否关闭 issue 由维护者决定。
背景
#1774:一个
@include *的普通脚本出现在弹窗「开启和运行的后台脚本」里(Android / Quetta,v1.4.0)。弹窗的后台列表直接读会话缓存
tabScript:-1,而RuntimeService.pageLoad用chromeSender.tab?.id || -1取标签页 id。页面不属于任何标签页时(sender.tab缺失,或tab.id为TAB_ID_NONE),id 就落成 -1,和后台脚本的命名空间撞在一起,于是这次页面上运行的普通脚本被记成后台脚本。如果是顶层 frame(frameId为 0),addScriptRunNumber还会先清空整个列表,把真正的后台脚本挤掉。另外,普通脚本一旦混进来就移除不掉,因为启用/禁用事件会跳过普通脚本,只能等浏览器重启清空会话缓存。本次改动
pageLoad只在页面属于真实标签页(tab.id > 0)时才上报popupPageLoadUpdate。拿不到所属标签页时,脚本照常下发执行,只是不记弹窗的运行计数。> 0沿用了PopupService现有的约定:markTabInjected、角标计数、updateScriptMenu都把tabId <= 0视为非真实标签页。getScriptsForTab本身不使用tabId,所以脚本在这类页面里的运行不受影响。已知限制
runNum === 0),这不是页面加载路径会产生的状态。它只可能来自两种情况:数据库里的type异常,或者用户在后台列表里点过「运行」。如果更新后仍能复现,需要沿这两条线另查。chrome.storage.session在扩展更新或浏览器重启时会被清空(Chrome 文档行为,未在本 PR 中实测)。验证
runtime.test.ts› 「pageLoad 页面运行计数只记到真实标签页」:没有 tab、tab.id为 -1 这两种情况下,仍返回脚本、不产生弹窗计数记录;真实标签页照常记录。前两条在撤掉修复后失败(2 failed),加上修复后通过。pnpm run typecheck通过;改动的两个文件eslint/prettier --check通过;提交时 pre-commit 钩子通过。pnpm exec vitest run --no-coverage src/app/service/service_worker/(rebase 到80854540之后):648 个用例中有 1~2 个失败,出现在trash_freeze.test.ts/trash_event_partition.test.ts/script.test.ts,每次失败的用例不同。拿origin/main版本的两个改动文件跑同样的命令,也会失败(script.test.ts+trash_freeze.test.ts+trash_event_partition.test.ts+runtime.test.ts连跑 3 次,每次 2/149 失败,用例轮换)。所以这是基线上已有的不稳定,与本改动无关;这几个文件单独跑时都能通过。origin/main80854540...b4d7b3cb)只有runtime.ts和runtime.test.ts两个文件。关联
Refs #1774