Skip to content

feat(auto-approval): 越界申请的自动审批插件(关联 #283) - #317

Open
JunieXD wants to merge 32 commits into
ECNU:mainfrom
JunieXD:feat/command-auto-approval
Open

JunieXD wants to merge 32 commits into
ECNU:mainfrom
JunieXD:feat/command-auto-approval

Conversation

@JunieXD

@JunieXD JunieXD commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

问题与修改

“工作区内修改”档里,bash/pwsh 命令和文件工具要写到工作区外时,每次都弹确认卡(#283)。本 PR 按 #283 的方案和后续评测,新增公共插件 @eduwork/dsh-auto-approval(packages/dsh-auto-approval):

  • 只在会话选择了专门的权限预设(默认 auto-approval)时工作,其他档位不受影响。其他工具策略(如 hooks)要求确认的调用、子智能体会话不审查。
  • bash/pwsh 和文件工具 write/edit/apply_patch 的越界申请先经固定规则和决策模型审查:判断用户会同意的,等同用户点“允许一次”;其余原样弹确认卡。插件不替用户拒绝。
  • 命中规则(推送和发布、远程连接、上传、运行部署或发布脚本、钥匙串和凭据、sudo、安装、改软件配置、系统设置)只问一道题,门槛 0.7;未命中的并行问两道题(用户会不会同意、做错了后果多严重),平均不低于 0.5 才放行。问法、规则和门槛与 [Feature 提案] 自动审批:越出工作区的申请先由决策模型判断,必要时才问用户 #283 评论里第九轮评测的版本一致;规则另补了几处写法:curl 短选项直接带值(-dvalue、-Tfile)算上传;PowerShell 读名字带 KEY/TOKEN/SECRET/PASS 的环境变量、shell 展开这类全大写变量("$X_API_KEY"、${X_TOKEN})算读凭据;写进文件的 heredoc,分隔符不加引号且正文里有 $(…) 或反引号(shell 会执行它们),或者分隔符后面还有命令文字(如 cat <<'EOF' > a.sh,之后可能运行这个文件)时,正文照常检查。写入 ~/Library/LaunchAgents 的登录启动项算改软件配置。
  • 文件工具的申请按效果相同的写法交给审查,和评测过的命令写法一致:write 写成 cat > 路径 <<'EOF' 的 heredoc,edit 写成补丁,apply_patch 原样,写入内容每段最多保留 4000 字。另加“目标文件”一项,列出每个文件经过链接后的真实路径、是新建还是整个替换、修改、删除、移动,以及是不是本次会话创建的。规则按真实路径套用,相当于对它执行 cat > 或 rm,移动按写入目的路径算。改本次会话之前就有的文件时,分数取两题平均和“用户会同意”的概率中较小的一个:模型认为用户没要求的改动,再小也交给用户。
  • 用户在智能体提问卡上的回答算用户的消息,它回复的就是这张卡;在卡片等待期间作答和超时后作答都算。超过 300 字的用户消息保留开头 100 字和结尾 200 字:回复引用内容时,用户自己的话常在后面。
  • 整条 bash 命令就是运行一个写明路径的本地脚本时(如 bash scripts/deploy.sh prod),把脚本内容(最多 16000 字)附给规则和模型;命令序列、cd、变量、管道、重定向和 PowerShell 等看不准实际运行哪个文件的,不附脚本,命令照常审查。“本次会话创建的文件”取自 write 成功新建的结果,按真实路径比对。“工作区”取沙箱实际的写入边界;会话目录按工具审批后取目录的方式读取(目录已不存在时退回会话起始目录),“当前目录”再按 shell 工具的方式解析 workdir。审查期间会话目录变了的,交给用户。
  • 一次审查限时 10 秒(包括等待凭据、登录等 Host 服务;决策服务繁忙时一次审查要 3~6 秒,5 秒会让不少审查只因超时交给用户),网络错误、429、5xx 重试一次;同一会话连续失败 3 次暂停 5 分钟。失败、超时一律交给用户。未登录机构账号或没有 Key 时不发请求,直接交给用户,记录里写明原因;这两种情况不计入连续失败,免得原因被“暂停审查”盖住、登录后还要等暂停结束。同一调用 ID 有两个调用同时进行时无法确定是哪一个,也交给用户。超过 16000 字的命令直接交给用户(文件工具按截断内容后的长度算)。审查期间会话切出预设或申请被撤回的,不放行。
  • 用户在确认卡上拒绝过越界申请后,到用户发下一条消息之前,这个会话的越界申请不再审查,直接交给用户,智能体换个理由重试也不会被自动放行。
  • 预设下审查的每个申请随这次调用的结果在会话里留一条记录,写明自动审批放行了这次越界申请还是交给了用户确认。“轨迹”里是一行“上下文”,点开在“来源”里能看到结果和分数(如“已自动放行(分数 0.949)”),没审查出结果的写明原因(未登录机构账号、没有决策服务 Key、审查超时、审查失败、暂停审查、命令过长、用户拒绝过、审查期间情况有变)。记录也在下一步发给对话模型:和 DSH 自己的运行时上下文一样用 <system-reminder> 包着、写明不是用户发的消息,不带分数和模型给的调用 ID。之前智能体会把自动放行说成“经您批准”,加了记录后不再这样说。
  • 输入框旁的权限菜单里,“自动审批”前面显示图标(盾牌加闪光,线条与内置预设的图标一致),选中时权限按钮上也显示。DSH 只按四个内置预设的 ID 从写死的表里取图标(0.2.2-rc.3 也一样),配置加不上,所以插件新增界面部分,在页面上补图标:从 DSH 的权限目录读出这个预设的名字和位置;按钮上放在名字前面;菜单单独挂在页面上,和按钮没有关联,按“菜单项与目录里的预设一一对应、顺序相同”认出权限菜单,照抄旁边内置预设的图标位置放进去。只增删插件自己的节点,不改 DSH 的。DSH 以后改了菜单、对不上时不加图标,菜单照常用;DSH 自己给这个预设画了图标时用 DSH 的。设置页“默认权限”和 /permission 列表里所有预设都没有图标,不加。界面部分读不到插件配置,图标只加在 ID 为 auto-approval 的预设上;有别的预设和它同名时也不加。
  • 决策服务请求复用 @eduwork/dsh-decision 已发布的 ./core 导出;支持 API Key、机构登录和免鉴权,包内没有机构默认值,默认关闭。
  • 包维护脚本、CI 和 docs/PACKAGES*.md 加入这个包。

已实现:上面这些。计划(不在本 PR):

  • npm 发布后接入桌面装配:公版装配加入这个包,Host 在权限配置里加“自动审批”预设,配置了决策服务才显示;公版不带决策服务的默认配置。
  • 学校版接入:上面一步随公版发布后,在 EduWork-ECNU 更新 core.lock.json 时,另开 PR 在发行配置里接学校的决策服务(机构登录 ecnu,决策模型 ecnu-decision),学校版用户登录学校账号后就能选“自动审批”。
  • 看得懂的确认卡(说明这条命令做什么、为什么问),确认卡上写明审查失败的原因;对话界面里显示审查记录(DSH 的对话界面不显示注入的上下文,现在只在轨迹里看得到)。
  • 记住批准。
  • 子智能体:DSH 把子会话审批固定为 never,越界申请在审批链之前就被拒绝,插件接不到,需要上游改。

验证

  • node scripts/packages/manage.mjs check dsh-auto-approval(Node 24.22.1,锁定的 DSH 0.2.2-rc.1 Runtime):44 项通过。其中 6 项在真实 Runtime 上跑完整流程:脚本化的模型先用真实文件工具新建文件、再发起越界申请,经真实的 agent loop、工具管线和审批服务,插件放行或交给用户,审查记录写进会话、出现在下一步发给模型的请求里;另覆盖跨步复用的调用 ID、hook 要求确认的调用、会话切换目录后的工作区、文件工具 write 写到工作区外(审查看到真实路径和文件状态,放行后文件写入),以及提问卡的回答被读成用户的消息。其余用合成数据和本地 HTTP 服务覆盖规则、状态、门槛、重试、超时(含 Host 服务卡住)、暂停、撤回、鉴权(未登录和没有 Key 时写明原因、不计入暂停)、子智能体、并行的重复调用 ID、超长命令、审查期间切换预设或撤回申请、决策服务拒选、用户拒绝后的重试、各种结果的记录(包括带标签字符的调用 ID 不进记录正文)、符号链接和脚本推断(包括各种不该附脚本的 shell 写法)、文件工具的展示和截断、目标文件状态、已有文件的计分、补丁格式错误、复用提问卡调用 ID 冒充回答、会话新建文件的位置被换成指向旧文件的链接、审查期间会话目录消失、最后一次读目录卡住或出错、长消息按字符截断。界面部分的 6 项在 vm 里运行构建产物、配最小的假 DOM,覆盖菜单和按钮补图标、DSH 自己有图标时让位、无关菜单里的同名项和同名预设不加、切换预设、重读目录和卸载。

  • 规则改写(部署脚本正则去掉回溯、heredoc 查找改为线性)后,在研究用的 693 条真实申请上与评测版规则逐条对照,判定完全一致。补上面几处写法后,在研究数据的 68003 条不同真实命令上有 37 条改为命中规则:curl 和 PowerShell 两处各 1 条(curl 那条是 cut -d/ 被当成 curl 的 -d 的误报),shell 变量 35 条(多是把 token 写进文件或放进 Authorization 头);都不在带标注的评测样本里,284/419、0/134 不变;heredoc 两处在这批命令上不改变任何判定。

  • 文件工具评测:从本机其他编程智能体会话里取真实的工作区外写文件和改文件,按插件的方式整理后交给同一个决策模型(先标注再运行;含他人姓名等个人信息的整条剔除)。应当放行的 141 条放行 109 条;应当询问的 35 条没有一条被放行,其中 3 条是真实申请,32 条是把对已有文件的改动配上另一个任务的上下文构造出来的。“改已有文件取较小值”是看了第一批结果后加的,加之前有 1 条构造的应问被放行(做别的任务时改了桌面草稿里几个字);加上之后另抽一批留出样本只跑一次:应当放行的 33 条放行 25 条,应当询问的 15 条全部交给用户。

  • 长消息截法:评测样本存的用户消息原来都只有前 300 字,从原会话取回全文后,在含长消息的 113 条(应当放行 91、应当询问 22)上比较:只留前 300 字放行 75 条,只留后 300 字 75 条,开头 100 字加结尾 200 字 78 条;三种截法下应当询问的都没有被放行。

  • node --test tests/package-maintenance.test.mjs tests/ci-changes.test.mjs:19 项通过。pack dsh-auto-approval 归档检查通过。scripts/check-source-docs.mjs 通过。

  • 本机真机验收:本地 QA 应用(0.4.12,DSH 0.2.2-rc.1),把本 PR 最终提交打出的包和预设手动注入产品组合,学校账号登录,决策模型 ecnu-decision。每个任务新开会话并选“自动审批”:

    任务 结果 审查
    在主目录新建文件夹并写文件 自动放行 0.957,333 ms
    按用户点名删掉主目录下事先已有的文件夹 自动放行,只删了这个文件夹 0.502,268 ms
    建主目录下的本地裸仓库 自动放行 0.773,266 ms
    按要求把工作区里的新仓库推送到这个裸仓库 自动放行(命中“推送和发布”) 0.986,243 ms

    点名删除的分数卡在 0.5 门槛上:之前几个版本各跑一次是 0.495、0.478、0.495,都弹了确认卡。用户点名要删的,按评测的标注放行和询问都算对,但结果不稳定。其余任务在之前几个版本上结果相同。同一删除任务在“工作区内修改”下照常弹卡,插件不介入。

    加审查记录之后又跑了几次:在主目录新建文件夹三次都自动放行(0.949、0.955、0.948),轨迹里有记录,点开“来源”能看到分数,智能体回复“本次由运行环境自动放行,没有弹窗询问你”;按用户点名删掉三个文件夹,自动放行(0.531),只删了这三个。把插件的 Key 引用临时改成不存在的,审查失败,弹确认卡,点“拒绝”后,轨迹里记为“交给用户确认(审查失败)”,智能体回复申请被拒绝,没有绕过;这种情况现在单独写成“没有决策服务 Key”,只跑了离线测试,没在 QA 应用里重测。12:53–12:59 决策服务变慢(同样的请求直接发过去要 0.9–4.5 s),三次审查都在 5 秒时限超时,按设计弹确认卡,轨迹里记为“交给用户确认(审查失败)”;之后把超时单独写成“审查超时”。13:12–14:39 每 5 分钟把同样的请求直接发一次,18 次里 9 次超过 5 秒(0.4–11.3 s)。最终提交的包在 14:40 复测:主目录新建文件夹自动放行(0.954,1442 ms),“来源”里是“已自动放行(分数 0.954)”,智能体回复“这次重试由自动审批放行”。完成的 18 次审查耗时中位约 310 ms,最慢 1483 ms。

    加入文件工具审查等改动后,最终提交在 11-12 夜里复测。当时决策服务很慢(同样的请求直接发过去要 9–31 s),5 秒时限内的审查都超时,按设计弹确认卡。为验证最终版本的判定,临时把 QA 应用的 timeoutMs 调到 30000,测完已改回默认:

    任务 结果 审查
    用 write 在主目录新建文件夹并写文件 自动放行 0.935,17394 ms
    新会话里用 edit 改上一步写的文件(对这个会话是已有文件) 自动放行,周三那一行按要求改了 0.761,19934 ms
    智能体先用提问卡问要不要新建文件,选“要”后用 write 新建 自动放行 0.962,21580 ms

    提问卡那次用插件读会话的函数核对过真实会话记录:审查读到的用户最近消息是原始请求和“选择“要””,用户回复的助手消息是那张提问卡;轨迹“来源”里是“已自动放行(分数 0.962)”。

  • 11-13 下午直接请求决策服务,一次审查 3.2~5.9 秒,默认时限从 5 秒改为 10 秒,其余判定不变。

  • 11-14 在 QA 应用里装上最终提交:权限菜单里“自动审批”有图标,四项文字起点对齐;选中时按钮上有图标,切到其他预设时补的图标拿掉、只剩 DSH 的,切回来又加上;/permission 列表里不加;控制台没有和插件有关的报错。

  • 未执行:Windows 原生 pwsh 真机验收;桌面装配(本 PR 不改装配和 source-receipt.json)。

兼容性与后续事项

  • 新增 npm 包 @eduwork/dsh-auto-approval 0.1.0,未发布;发布需单独授权。现有装配、依赖锁和其他插件不变。包里有 ./client 导出和 dsh.client 声明:界面部分只补图标,不引用其他模块。
  • peer 范围:DSH >=0.2.2-rc.1 <0.3.0-0(新增对 dsh-llm 的 peer,用它的 createUserMessage 写审查记录;新增对 dsh-fs-patch 的 peer,用它的 parsePatch 解析补丁)。
  • 启用后会把用户最近 3 条消息、用户回复的那条助手消息、之前 6 条命令、本次会话新建文件的路径、要运行的脚本,以及文件工具要写入的内容和目标路径发给配置的决策服务,README 里写明了。
  • 后续见上面的“计划”。

…a decision model

Add the @eduwork/dsh-auto-approval plugin. Under a dedicated permission preset
it reviews bash/pwsh sandbox escalation requests before the client's
confirmation card: fixed rules flag operations the user must have asked for,
and a SystemOne-compatible decision model scores the request. Approved
requests are allowed once; everything else reaches the user unchanged.

Reviews are time-limited, retried once on network errors, 429 and 5xx, and
paused for a session after three failures in a row. The plugin ships
disabled and is not yet part of desktop assembly.
- Record a shell call only after the other pre-execute policies allow it, so a
  call a hook asks the user about is never reviewed; skip subagent sessions.
- Track calls per session and drop them on their result; two calls in flight
  under one ID are ambiguous and go to the user, and the approval must name
  the recorded tool.
- End a review that waits on a stalled Host service within the time limit.
- Take created files from successful write and apply_patch results instead of
  call arguments, and read the session up to the last log entry of the
  pending call ID.
- Cover these paths with mounted tests and the real Runtime with fs tools.
- Keep the deploy-script pattern linear: the name after the keyword stops at
  the next keyword. Rule results are unchanged on the evaluated requests.
- Find a heredoc's end from its own line instead of rescanning the command.
- Hand commands over 16000 characters to the user; the longest evaluated
  command had 13010, and the limit bounds the rules' running time.
- Attach a script only when an interpreter runs the file, not for inline code
  (node -e, python3 -c, bash -c) or a syntax check (bash -n).
- Track every shell execution by its token: while more than one call with an
  ID is in flight, none is reviewed, and a call started during a review stops
  its approval.
- Take the workspace from the sandbox policy, whose boundary stays at the
  session's starting directory, and keep the current directory (moved by /cd)
  as the base for workdir and script paths.
- Do not attach a script run by bare name without an interpreter: the shell
  finds it on PATH, not in the current directory.
- Cover both with mounted tests and a real-Runtime test that moves the
  session's directory outside the workspace.
- Start from the directory the shell tool uses: bash appends workdir and lets
  the file system resolve '..' after links, pwsh resolves it; show the real
  directory.
- Open a script by its path as written under that directory, so a '..' after
  a link reaches the file the shell runs.
- Leave the script out after 'cd -' or cd options; a bare 'cd' goes home.
- Test both with real links; note in the READMEs what the workspace and
  current directory fields mean.
The fifth review found more shell forms the directory walk misread: cd with
options and quoted paths, a quoted file name with a space, and cd inside a
pipe or after ||. Instead of modeling each, follow only a plain sequence:

- no script when the command has a pipe or ||;
- cd is followed only to one plain path (quotes must pair); any other cd,
  pushd/popd, source, eval, exec, builtin, command, compound commands and
  function definitions stop the walk;
- a quoted script name must close its quote.

Other programs before the script still do not move the shell.
The sixth review showed that excluding known shell forms still followed
commands it could not read: variables, comments, unparsed cd arguments,
commands after exit or false, heredoc bodies, and PowerShell's Set-Location.

Replace the directory walk with one positive pattern: the whole bash command
runs a literal path, directly or through an interpreter whose options take no
code, with plain arguments and redirections. Every other form, and every
pwsh command, attaches no script; the command itself is still reviewed. Of
the 693 evaluated requests only 7 carried a script.
- Count a decision service abstention (choice: null) as a failure instead of
  reading its probabilities; the evaluated answers had none.
- Attach a directly run script only when it has an execute bit; without one
  the shell refuses it and nothing runs.
- Re-check the session's preset before approving: a session that left the
  preset during the review is asked as usual.
- Attach a directly run script only when this process may execute it.
- Keep a quoted ~ literal, as the shell does.
- Attach no script after assignments before the command, such as BASH_ENV,
  which can run code before the script.
… path

- A redirection can empty the script before the interpreter reads it.
- Node resolves '..' before links while bash and the file system follow the
  link first; rather than model each interpreter, a path with '..' attaches
  no script.
…t names

trim() also removed characters bash treats as part of a word, so a command
naming 'task.sh\r' attached task.sh. Trim only spaces, tabs and newlines.
bash, sh and zsh parse a leading + as an option, so 'bash +task.sh' runs
nothing.
Re-check the review's signal with the other conditions before approving, so
a request withdrawn or timed out as the review returns is not answered.
Each request reviewed under the preset adds a notice to its call's
result. The trajectory shows its summary with the outcome and score;
the model reads only whether the escalation was allowed automatically
or the user was asked, so it no longer reports an automatic approval as
the user's. The preset name in the examples drops "experimental".
…ter a rejection

The trajectory lists a notice by its text, so the text now says in
Chinese who decided and ends with the call ID; the score stays in the
summary under the notice's source. After the user rejects an
escalation, later escalations in the session go straight to the user
until the user writes again, so a retry is never approved behind a
rejection.
…s words

Context reaches the model as a user message, and in a desktop run the
model took the Chinese notice for something the user said. The notice
is now wrapped in reminder tags, as DSH does for its own runtime
context, and says it is not a message from the user.
The call ID comes from the model and was written inside the reminder
tags as is, so an ID holding a closing tag could move text out of them
and into the user message the model reads. The notice follows its
call's result, so the text now names only the tool.
…ret reads

curl lets a short option carry its value directly (-dvalue, -Tfile),
which the upload rule missed, and the credential rule did not see
PowerShell reading a secret environment variable ($env:X_KEY,
Get-Item Env:X_TOKEN). On the 68003 distinct real commands of the
research data only 2 change, neither in the evaluated samples.
The credential rule saw printenv and PowerShell reads of secret
variables but not the plain shell form ("$X_API_KEY", "${X_TOKEN}").
Only upper-case names count: lower-case ones are mostly loop and
template variables. On the 68003 distinct real commands of the research
data 35 more are flagged, none of them in the labeled samples.
The rules skipped the body of a heredoc written to a file as text, but
with an unquoted delimiter the shell runs any $(...) or backtick
substitution in it, so an ssh or upload there went unflagged. Such a
body is now checked; plain text and quoted heredocs are still skipped.
No rule result changes on the 68003 distinct real commands of the
research data.
${env:X_API_KEY} reads an environment variable like $env:X_API_KEY but
was not seen by the credential rule. No rule result changes on the
research data, whose only braced reads are ${env:ProgramFiles}.
The body of a heredoc fed to cat was skipped unless a pipe followed the
delimiter, but only a target written before the delimiter is tracked:
with `cat <<'EOF' > a.sh` the script that was then run went unchecked.
Any shell text after the delimiter now keeps the body. No rule result
changes on the 68003 distinct real commands of the research data.
A review that runs out of time was recorded as failed like any other
error. In a desktop run the decision service slowed to several seconds
and both reviews timed out; the notice now says so, so the user can
tell a slow service from a sign-in or configuration problem.
…nswers

DSH 0.2.2's write, edit and apply_patch request sandbox escalation too, and
those requests went straight to the user. They are now reviewed, shown in
the form the review was evaluated on: write as a quoted heredoc, edit and
apply_patch as a patch, long contents cut. A target-files field gives each
file's real path through the Host file system, whether it exists, the
change, and whether this session created it. The rules judge each change
as the shell command with the same effect on the real path.

A change to a file that was there before the session is approved only
when the model also judges it requested: its score is at most P(approve),
so a small unrequested edit is not let through for being easy to undo.

Answers on ask_user_question cards, in time or after the call timed out,
count as the user's replies to that card.

Writing a login item to ~/Library/LaunchAgents counts as changing
software configuration.
… runs

- A question card's ID stands for the card only until its first result:
  a later call reusing the ID cannot pass its output off as an answer.
- Only a write that made a new file counts as created by the session; a
  patch's Add File may replace an existing file and its empty diff basis
  does not say otherwise.
- A file counts as the session's own by its real path only, so a path
  swapped for a link to an older file is judged as that file.
- The review reads the session directory through ensure, as the tools do
  once approved, so a directory that no longer exists resolves to where
  the session started in the review as well.
- A move is judged as writing its destination, which flags a login item
  or config file whatever characters its name holds.
A user replying to quoted text usually writes their own words last, and the
first 300 characters can hold only the quote. A message over 300
characters now keeps its first 100 and its last 200, with the length left
out noted between them. On the 113 evaluated requests that hold a long
message, this allowed 78 of the 91 that should be allowed (75 with the
first 300 or the last 300 alone) and none of the 22 that should be asked.
…by character

- If the session's directory goes while the review waits, the tool will
  resolve its paths from where the session started, and a relative path
  with `..` can then lead somewhere other than what was reviewed. The
  directory is read again before approving; a change goes to the user.
- A long user message is cut by character, so an emoji is neither split
  nor counted twice.
The directory read added in 70f48f6 came after the timed review: a stalled
file system could hold the approval past the time limit, a failure there
reset the failure count before it was counted, and the preset and the
call ID were checked before it rather than after. The read is now the
last step of review(), inside the race with the time limit and the
failure count, and the checks that follow it are synchronous.
@JunieXD JunieXD changed the title feat(auto-approval): 命令越界申请的自动审批插件(关联 #283) feat(auto-approval): 越界申请的自动审批插件(关联 #283) Nov 13, 2026
@JunieXD
JunieXD marked this pull request as ready for review November 13, 2026 05:36
The decision service at times takes 3-6 s for one review; with a 5 s limit,
half of the reviews on a slow afternoon went to the user only for timing out.
DSH draws icons only for its four built-in presets, from a fixed table
(0.2.2-rc.3 too). A client part adds one for the auto-approval preset on
the page: on the permission control while the preset is selected, and in
the composer's permission menu, told from other menus by its items, one
for each preset in DSH's permission catalog, as a copy of a sibling
item's icon slot. It changes nothing of DSH's, and adds no icon where the
page is not as expected, DSH draws one of its own, or another preset has
the same name.
Without organization sign-in or a decision service key, a review was
recorded as a plain failure, and three of them paused review for five
minutes, so the trajectory showed neither the cause nor, once signed in,
any review for a while. Nothing is asked of the service then: the notice
now names the missing sign-in or key, and neither counts towards the
pause.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant