Repository navigation
Commit e6a5ecb
chore(claude): allow-list hotcrm REST rows and the issue-create / issue-transfer tools (#19941)
Fixes #19931
Clause-②: no
A `repo:hotcrm` seat in a cloud container had no allow rule for its own
lane: every read and write went to the auto-mode classifier. This PR
adds the hotcrm allow rows and the two missing tool rows. It also writes
the four facts a seat needs into `rest-channel.md`. The maintainer's
ruling on the card, verbatim: 「你的问题开skills卡」. The `domain:skills` seat
set the shape.
## What changed
### `.claude/settings.json` (`permissions.allow` only; the deny roster
and hooks are untouched)
- **13 hotcrm rows.** Each of the 13 `objectstack-ai/objectui` REST rows
is now followed directly by the same verb and path shape for
`objectstack-ai/hotcrm`. The mirror covers:
- the label POST and every GET row (issues list, issue, comments,
labels, pulls, files, commits, check-runs);
- PATCH pulls;
- the two ccr landing routes (`ready_for_review`, `auto_merge`);
- PATCH issues.
- **Per-repo rows, not an org wildcard.** The rows name each repo
instead of `objectstack-ai/*`. The per-repo shape is the only one tested
so far. Whether a wildcard `*` in a permission rule crosses a `/` has
not been tested. This is the open question below.
- **4 tool rows.** `issue-create.mjs` and `issue-transfer.mjs` each get
the bare row and the `--use-env-proxy` row, next to the three existing
tool pairs:
- `Bash(node scripts/pm/issue-create.mjs *)` and `Bash(node
--use-env-proxy scripts/pm/issue-create.mjs *)`
- `Bash(node scripts/pm/issue-transfer.mjs *)` and `Bash(node
--use-env-proxy scripts/pm/issue-transfer.mjs *)`
- **Deliberately no row for `scripts/pm/fleet-write/dispatch.mjs`.** A
bare dispatch skips what the per-op tools do: the stamp, the
unread-knock check and the read-back. It also skips the fleet write-pace
budget. Batching goes through the per-op tools: `close-cards.mjs --plan`
closes many cards in one run, and `label-write.mjs` handles one card per
call.
Structural check on the result: 13 objectui rows and 13 hotcrm rows,
each hotcrm row directly after its objectui twin; the JSON parses.
### `.claude/skills/pm-dispatch/references/rest-channel.md`
The four facts are written into existing lines. The file stays at 82
lines, the ceiling. No line was added, no line was re-wrapped, and every
line stays at or under 120 bytes.
| line | bytes before → after | fact |
|---|---|---|
| 11 | 116 → 116 | (a) the relay selector serves **five** write tools,
not four (`post-stamped`, `label-write`, `close-cards`, `issue-create`,
`issue-transfer`, the five that import `resolveRoute`) |
| 14 | 117 → 117 | (c) `OS_FLEET_SESSION`, any variable assignment, and
`cd … &&` all fall to the classifier when used as a command prefix; in a
multi-repo cloud session, the seat's first call is a bare `cd
/home/user/objectstack` on its own |
| 17 | 73 → 117 | (d) batching always goes through the per-op tools;
`dispatch.mjs` has no allow row (the op-table path is shortened to
`fleet-write/ops.mjs` to fit) |
| 19 | 111 → 113 | (b) a failed relay run books 5 (the `exitForResult`
register used by `label-write`, `issue-create`, `issue-transfer` and
`dispatch.mjs` itself). Two exceptions: `post-stamped` books 4, and
`close-cards` books 4 when the board shows a step landed or the card
cannot be read back. UNCONFIRMED is 6. |
Line 14 used to say that allow rules are literal prefixes. That rule is
still stated in this file: the 〈写侧〉 heading on line 39 says 允许规则按首个 glob
前的字面前缀匹配. The only text dropped is the consequence tail 席位就此卡死.
Exit codes were checked against each tool's code, not just its header:
- `post-stamped` `relayExitFor({state:'failure'})` gives
`EXIT_NOT_STORED` = 4.
- `close-cards` reads the board after a failed run: 5 when nothing
landed, 4 (`EXIT_HALF_WRITE`) when some steps landed or the read-back
failed. Its self-test battery "the relay miss" pins this.
- `label-write`, `issue-create` and `issue-transfer` all return
`exitForResult(sent)`, which gives 5 for a failed run.
`lanes/hotcrm.md` is untouched. The cwd and prefix fact applies to every
sister-repo seat in a multi-repo session, not only to hotcrm, so it
belongs in `rest-channel.md`.
## Verification (at HEAD `6b230972`)
Gates came from `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` run in the worktree (18 commands), plus the
dispatch's `node scripts/check-skills-token-ratchet.mjs`. Every exit
code was captured before any pipe. `--ran` result: `✓ dispatch-gates
--ran: 18 derived famil(ies) accounted for — 18 run, 0 NOT-MEASURED`.
| gate | exit | verdict line |
|---|---|---|
| `pnpm check:pm-settings-deny-roster` | 0 | `17 content-write tool(s)
declared = enforced in .claude/settings.json` |
| `pnpm check:pm-skill-ratchet` | 0 | `rest-channel.md is 82 lines
(ceiling 82; headroom 0)` |
| `pnpm check:pm-skill-id-lint` | 0 | `34 file(s) clean` |
| `pnpm check:nul-bytes` | 0 | `scanned 9346 text file(s) … no raw ASCII
control bytes` |
| `node scripts/check-skills-token-ratchet.mjs` | 0 | `54 authored
bundle file(s) within their ceilings` |
| `pnpm check:skill-frame-sync` | 0 | green |
| `pnpm check:doc-authoring` | 0 | green |
| `pnpm check:pm-governed-merges` | 0 | green |
| `pnpm --filter @objectstack/lint run check:doc-formula-expressions` |
0 | the first run exited 3 (PREREQUISITE NOT MET, formula and lint
`dist` not built); after `turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint` under the verify lock, it exited 0 |
| the other 10 derived commands | 0 | green |
NOT MEASURED: the auto-mode classifier's verdict on the new rows. The
classifier only runs inside a live seat session. The first live use will
be the `repo:hotcrm` seat running its confirmed group.
The deny-roster gate does not check the `allow` list. Its header says so
("That `allow` and `deny` agree … is deliberately NOT asserted"), so its
green says nothing about the new rows. No gate reads the allow list's
membership. That check rests on the structural mirror above, and this PR
adds no gate.
## Open question for the maintainer
Should an org-level wildcard (`objectstack-ai/*`) replace the per-repo
rows? This PR keeps per-repo rows, the only tested shape. A wildcard
would also cover any future sister repo without an edit. Whether `*` in
a Bash permission rule matches across `/` has not been tested, and the
classifier cannot be tested offline.
## Acceptance notes
- `.claude/settings.json` is read from the primary checkout when a
session starts, and is not reloaded
(`scripts/pm/check-harness-current.mjs`). The new rows take effect for a
seat only in a session that starts after the primary checkout includes
this merge.
- `scripts/pm/close-cards.mjs` header, lines 37–38, also suggests "name
the script with an absolute path and nothing before it". No allow rule
names an absolute path, so that spelling falls to the classifier. This
is the card's seat-side bullet 2. It is reported to the seat, not fixed
here.
- `rest-channel.md` line 63 still says the transfer recipe lives in
`platform-readings.md`. The door is now `scripts/pm/issue-transfer.mjs`
(`cross-repo-coordination.md` line 25). Line 12 says `otherwise direct`,
but an indeterminate relay read is an exit-3 refusal. Both lines are
outside this PR's lines.
- AGENTS.md lists the tools that own their writes as `issue-create`,
`label-write`, `post-stamped` and `close-cards`, without
`issue-transfer`. It is outside this PR's file surface (Tier H).
## 维护者速读(草稿)
**改了什么**:`.claude/settings.json` 的放行清单给 hotcrm 仓补上与 objectui 一模一样的 13 条
REST 读写规则。建卡(`issue-create`)、转仓(`issue-transfer`)两个写工具各加两种拼法的放行规则。中继的裸
`dispatch.mjs` 刻意不放行。`rest-channel.md`
就地改了四处:写工具现为五个;中继失败的退出码按现行工具更正;多仓云会话里席位先单独一条 `cd
/home/user/objectstack`,命令前不带任何前缀;批量一律走逐 op 工具。文件行数 82 不变,没涨上限。
**为什么改**:维护者原话「你的问题开skills卡」。hotcrm
席位在云会话里的读写全凭分类器裁量。第一笔写被拒之后,连读都被拒,已确认的十卡批次至今没执行。
**风险与代价(含回滚)**:本 PR 只加放行规则,放行面与 objectui 已有的完全相同,不新增能力。之后 hotcrm 的 REST
写不再经分类器判,包括 PR 转 ready、挂 auto-merge、改卡。分类器离线测不了,首次实测是 hotcrm
席位执行已确认批次。设置在会话启动时从主检出读取,合并后新开的会话才生效。回滚 = revert 本 PR。
**席位意见**:
**你要做的**:拍板一个问题:要不要用 org 级通配 `objectstack-ai/*` 代替逐仓行(本 PR 没采用,因为通配是否跨
`/` 没实测过)。本 PR 属 Tier S,由席位凭合约复核记录走队列落地,不需要你点批准。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01A22sUB3mUWs6M36VgfijBq)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 43460b9 commit e6a5ecb
2 files changed
Lines changed: 22 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
| 36 | + | |
35 | 37 | | |
36 | 38 | | |
| 39 | + | |
37 | 40 | | |
38 | 41 | | |
| 42 | + | |
39 | 43 | | |
40 | 44 | | |
| 45 | + | |
41 | 46 | | |
42 | 47 | | |
| 48 | + | |
43 | 49 | | |
44 | 50 | | |
| 51 | + | |
45 | 52 | | |
46 | 53 | | |
| 54 | + | |
47 | 55 | | |
48 | 56 | | |
| 57 | + | |
49 | 58 | | |
50 | 59 | | |
| 60 | + | |
51 | 61 | | |
52 | 62 | | |
53 | 63 | | |
| 64 | + | |
54 | 65 | | |
| 66 | + | |
55 | 67 | | |
56 | 68 | | |
57 | 69 | | |
58 | 70 | | |
59 | 71 | | |
60 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
61 | 77 | | |
62 | | - | |
| 78 | + | |
| 79 | + | |
63 | 80 | | |
64 | 81 | | |
65 | 82 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
| 17 | + | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
0 commit comments