Repository navigation
Description
来源: #465 分析 wildcard 覆盖 acp_status 问题时发现。同一家族的根因(key-presence vs rule-resolution)在 compress defer 守卫上还有一个残留实例;#457/#465 的修复按 owner 范围只改了 acp_status 默认写入,此处是设计决策而非机械 bug 修复,故立项待 owner 拍板。
Observation
After #457/#465 (PR #466), the acp_status default write is gated on rule resolution (anyRuleResolves). The sibling guard for the compress key — hasExplicitToolPermission(permissionConfig, "compress") inside applyAcpToolPermissions (lib/host-permissions.ts) — is still plain key presence. Consequence: a user wildcard decision that resolves compress but is not a deny does not defer:
// user opencode.json
{ "permission": { "*": "ask" } } // no explicit compress key
// ACP config: default (compress.permission: "allow")Flow on current code:
compressDisabledByOpencode({ "*": "ask" })→false(onlypattern==="*" && action==="deny"self-disables) → no self-disable.applyAcpToolPermissions: no owncompresskey → appendscompress: "allow"after the user's"*": "ask".- Host last-match resolution:
compressmatches both"*": "ask"andcompress: "allow"; the appended rule is later → allow wins.
Net effect: the user's ask on compress is silently upgraded to allow.
Severity: LOW — design question, not a regression
- The safety-critical direction is already covered: wildcard or exact
denyoncompresstriggers the self-disable path (compressDisabledByOpencode,lib/host-permissions.ts:71, which itself uses rule resolution) and ACP stops offering the compress tool entirely. - Only
ask(and redundantallow) resolutions are affected; practical impact is one fewer confirmation prompt on the compress tool. - Not introduced by PR fix: respect user decisions on permission.acp_status in host config write (#457, #465) #466 — behavior is identical before and after it.
Why filed rather than fixed in PR #466
Extending the defer guard to rule resolution (anyRuleResolves(…, "compress")) would change defer-by-design semantics beyond the owner-scoped #457/#465 fix: every config where a wildcard merely happens to cover compress would stop receiving ACP's own compress permission from ACP config. That is a semantic choice, not a mechanical fix.
Options
- Keep current semantics (defer = exact key only). Rationale: ACP's own
compress.permissionconfig is the authoritative knob for the compress tool; a blanket wildcard is a general catch-all, unlikely to express fine-grained intent for ACP's internal tool. Cost: the ask→allow silent upgrade remains. - Extend defer to any rule resolving
compress(reuseanyRuleResolves). Consistent with the [BLOCKER][V1] Явныйpermission.acp_status: "deny"молча переписывается в"allow"#457/MINOR: the #457 fix only covers the exact own-key case — a user wildcard decision on acp_status is still overwritten #465 principle — ACP never writes a decision over a user rule that resolves the tool. Cost: behavior change for existing users, e.g.{ "*": "ask" }+ ACP default allow → compress becomesaskinstead ofallow(a tightening, matching stated user intent). - Asymmetric (defer on
ask/deny, not onallow) — rejected: inconsistent and hard to explain.
Recommendation: option 2. The same root-cause family (key presence vs rule resolution) was judged wrong for acp_status in #457/#465; leaving the sister guard key-based keeps an incoherent split inside the same function. Since it widens defer behavior for existing users, it needs an explicit owner decision.
No PR attached — design question for the owner.
Activity
ranxianglei commentedon Sep 29, 2026
[bot] 🏷 Verified the observation against the current PR #466 head — it holds exactly as described. Assessment and recommendation below; no code changes made, waiting for your call.
Verification (PR #466 head
087e25cf, still open / unmerged)The split is confirmed at
lib/host-permissions.tson the branch tip, adjacent lines:Traced
{ "permission": { "*": "ask" } }end-to-end through the config hook (index.ts):compressDisabledByOpencode,index.ts:226) →false(action isask, notdeny) → no self-disable. ✓compresskey →applyAcpToolPermissionsappendscompress: "allow"after the user's"*": "ask". ✓asksilently upgraded toallow. ✓Also confirmed: identical before and after PR #466 (not a regression), and
denyremains safe via the self-disable path, which uses rule resolution.One addition beyond the issue body: ACP never writes host permission entries for
decompress,search_context, oracp_context_recap— user wildcards already govern those three today. Under current semanticscompressis the only ACP tool where a user wildcard is ignored, purely because ACP has a configurable knob for it. That asymmetry cuts toward option 2.Duplicate screen: no other open issue/PR covers this. The family is now complete and accounted for: #457 (exact key,
acp_status) + #465 (wildcard,acp_status) → both fixed in PR #466; PR #469 (fix(v2)) handles the same root cause on the retired V2 path; #472 is the last instance on the live 1.x path.Assessment
Option 1's core rationale — "a blanket wildcard is unlikely to express fine-grained intent for ACP's internal tool" — applies with equal force to
acp_status, yet #457/#465 decided the wildcard wins there. Accepting the principle for one tool and rejecting it for its sibling is exactly the incoherent split this issue flags.The deeper point: the host resolver treats
"compress": "ask"and"*": "ask"identically — both are "a user rule resolves compress". ACP's defer guard asks a different question ("is there an exact key?") than the system it writes into ("does any rule resolve?"). That divergence is the very root-cause family we just judged wrong twice.Blast radius is provably minimal — every cell checked:
compresskey (any value form)anyRuleResolvesshort-circuits on key presence first)compressacp_statusdefault)denyresolvingcompressdeny, tool unregistered; appended entry inertallowresolvingcompressallowwins last-match → allowallow— same effective resultaskresolvingcompress(e.g."*": "ask")allowwins → silent ask→allow ❌ask✅The only effective behavior change: users with a wildcard
askcoveringcompressstart getting prompted — a tightening that matches their stated posture. Anyone wanting today's behavior can pin an explicitcompress: "allow"key, which defers under both options. On prompt fatigue: a user who set"*": "ask"is already confirmed on every bash/edit/write call; one more confirmation class is consistent with their choice, not a new kind of friction.Recommendation: option 2
Agree with the issue's recommendation. It completes the #457/#465 principle (ACP never writes a decision over a user rule that resolves the tool) instead of carving out an exception for one tool, and aligns
compresswith how all of ACP's other tools already behave under wildcards.Implementation plan if you approve (small, surgical):
lib/host-permissions.ts— one-line guard swap:hasExplicitToolPermission(…, "compress")→anyRuleResolves(…, "compress"); update the doc comment (it currently claims "An explicit usercompressrule means the user owns the map").tests/host-permissions.test.ts— RED→GREEN per project convention: wildcard-ask defer, wildcard-allow defer, non-matching wildcard still gets the write, own-key cases unchanged.Waiting on two decisions: (a) option 1 vs 2, (b) PR #466 vs a separate PR.
中文摘要:已在 PR #466 当前 head(
087e25cf,未合并)上核实残留属实——compress的 defer 守卫仍是 key-presence,而acp_status已改为规则解析;建议采纳方案 2(defer 扩展到任何能 resolvecompress的用户规则),唯一实际行为变化是通配符ask不再被静默升级为allow(deny/allow 路径均不变),实现为一行守卫替换 + 测试,建议并入尚未合并的 PR #466;尚未改任何代码,等你拍板。