Skip to content

Commit e6a5ecb

Browse files
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

File tree

‎.claude/settings.json‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,54 @@
2929
"Bash(agent-browser skills *)",
3030
"Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/objectstack/issues/*/labels *)",
3131
"Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/objectui/issues/*/labels *)",
32+
"Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/hotcrm/issues/*/labels *)",
3233
"Bash(curl -sS -X GET https://api.github.com/rate_limit *)",
3334
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues?* *)",
3435
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues?* *)",
36+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues?* *)",
3537
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues/* *)",
3638
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues/* *)",
39+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues/* *)",
3740
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues/*/comments* *)",
3841
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues/*/comments* *)",
42+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues/*/comments* *)",
3943
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues/*/labels* *)",
4044
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues/*/labels* *)",
45+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues/*/labels* *)",
4146
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/* *)",
4247
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/pulls/* *)",
48+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/pulls/* *)",
4349
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/files* *)",
4450
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/pulls/*/files* *)",
51+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/files* *)",
4552
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/commits* *)",
4653
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/pulls/*/commits* *)",
54+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/commits* *)",
4755
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/commits/*/check-runs* *)",
4856
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/commits/*/check-runs* *)",
57+
"Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/commits/*/check-runs* *)",
4958
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectstack/pulls/* *)",
5059
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectui/pulls/* *)",
60+
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/hotcrm/pulls/* *)",
5161
"Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/ccr/ready_for_review *)",
5262
"Bash(curl -sS -X PUT https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/ccr/auto_merge *)",
5363
"Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/objectui/pulls/*/ccr/ready_for_review *)",
64+
"Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/ccr/ready_for_review *)",
5465
"Bash(curl -sS -X PUT https://api.github.com/repos/objectstack-ai/objectui/pulls/*/ccr/auto_merge *)",
66+
"Bash(curl -sS -X PUT https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/ccr/auto_merge *)",
5567
"Bash(node --use-env-proxy scripts/pm/post-stamped.mjs *)",
5668
"Bash(node --use-env-proxy scripts/pm/label-write.mjs *)",
5769
"Bash(node scripts/pm/post-stamped.mjs *)",
5870
"Bash(node scripts/pm/label-write.mjs *)",
5971
"Bash(node scripts/pm/close-cards.mjs *)",
6072
"Bash(node --use-env-proxy scripts/pm/close-cards.mjs *)",
73+
"Bash(node scripts/pm/issue-create.mjs *)",
74+
"Bash(node --use-env-proxy scripts/pm/issue-create.mjs *)",
75+
"Bash(node scripts/pm/issue-transfer.mjs *)",
76+
"Bash(node --use-env-proxy scripts/pm/issue-transfer.mjs *)",
6177
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectstack/issues/* *)",
62-
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectui/issues/* *)"
78+
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectui/issues/* *)",
79+
"Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/hotcrm/issues/* *)"
6380
],
6481
"deny": [
6582
"mcp__github__issue_write",

‎.claude/skills/pm-dispatch/references/rest-channel.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
- ✓ 按席位类别限定:每个 ✓ = 会话门开着的席位实调通过,⛔ 无 ✓ 不当已验证事实。
99
- 403 后 `/rate_limit` 判凭据形态:15000/时 = 凭据活被 repo-scoping 拒;60/时或 auth 错 = 无凭据。
1010
- 两只桶:MCP 记链接用户 5000/时,兄弟会话共享同桶;REST/CCR 记 App 安装 15000/时。
11-
- `objectstack-fleet[bot]` 经 `fleet-write` 中继:四个写工具与 `with-fleet.sh --via auto` 共一选择器。
11+
- `objectstack-fleet[bot]` 经 `fleet-write` 中继:五个写工具与 `with-fleet.sh --via auto` 共一选择器。
1212
- 三条件全立才 `dispatch`:`CCR_AGENT_PROXY_ENABLED=1`、会话 id、中继活着;否则 `direct`,印一行。
1313
- 会话 id 由容器 `CLAUDE_CODE_REMOTE_SESSION_ID` 派生;`OS_FLEET_SESSION` 只覆盖本地检出与测试。
14-
- ⛔ 永不把它前缀在命令前:允许规则是字面前缀,带前缀的写落到分类器,席位就此卡死。
14+
- ⛔ 它、赋值与 `cd … &&` 前缀都落分类器;多仓云会话首调单独裸 `cd /home/user/objectstack`。
1515
- 活着 = 工作流文件在 `main` 且 Actions 状态 `active`;维护者在 Actions UI 停用即整队回 `direct`。
1616
- dispatch 带会话令牌发往 objectstack;run 在 runner 上以逐次铸造、窄到目标仓的 App 令牌执行。
17-
- 闭合 op 表住 `scripts/pm/fleet-write/ops.mjs`;读侧不走中继。
17+
- 闭合 op 表住 `fleet-write/ops.mjs`;读侧不走中继;批量恒走逐 op 工具,`dispatch.mjs` 无 allow 行。
1818
- 正文超 60,000 字节的那一笔 `post-stamped` 写走 `direct` 并印一行,身份是席位自己的用户。
19-
- run 失败(post-stamped/close-cards 4,label-write/issue-create 5)与 UNCONFIRMED(6)只读,⛔ 永不重试。
19+
- run 失败记 5(post-stamped 4,close-cards 有步落地或读不回 4),UNCONFIRMED 6:只读,⛔ 永不重试。
2020

2121
## 读侧 —— 全部可迁移
2222

0 commit comments

Comments
 (0)