From a3b6d392f52e90bad3d4cc97952f55510eb67e9a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 06:29:56 +0000 Subject: [PATCH 1/5] pm-dispatch: register objectstack-ai/mobile as an on-demand repo lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mobile app is now a native shell that hosts the Console (objectstack-ai/mobile#144). Register it so its cards can be dispatched: - GOVERNED_REPOS gains `mobile` (its workflows stay outside the scoped workflows row, as hotcrm's do); self-test pins move five -> six - references/lanes/mobile.md: the repo:mobile seat charter — summoned on demand, no patrol routine; business UI stays in the Console, the shell takes native capability only; Console defects filed at the platform - ensure-pm-labels.sh: the pm vocabulary loop includes mobile - seat words and the single-lane repo list name mobile - line ratchet: rows for the new charter at its landed count Claude-Session: https://claude.ai/code/session_01Q4EjjRHkJgnuLkU9vVgHHR Co-authored-by: Claude --- .../references/cross-repo-coordination.md | 2 +- .../pm-dispatch/references/lanes/mobile.md | 49 +++++++++++++++++++ .../pm-dispatch/references/project-forms.md | 2 +- scripts/pm/check-governed-merges.mjs | 17 ++++--- scripts/pm/check-skill-line-ratchet.mjs | 6 +++ scripts/pm/ensure-pm-labels.sh | 9 +++- 6 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 .claude/skills/pm-dispatch/references/lanes/mobile.md diff --git a/.claude/skills/pm-dispatch/references/cross-repo-coordination.md b/.claude/skills/pm-dispatch/references/cross-repo-coordination.md index d88c8053809..567798ee429 100644 --- a/.claude/skills/pm-dispatch/references/cross-repo-coordination.md +++ b/.claude/skills/pm-dispatch/references/cross-repo-coordination.md @@ -2,7 +2,7 @@ - 产品依赖方向固定:`objectstack`(后端与 `ui/` 前端,`packages/spec` 唯一契约)→ `cloud`、`hotcrm`。 - 多车道仓 `objectstack`:中央分诊唯一生产 `domain:*`/type/定级,定级例外见 triage-duties 自分诊。 -- 单车道仓 `cloud`、`objectos`、`hotcrm`、`www.objectos.ai`;未来新仓默认此类。 +- 单车道仓 `cloud`、`objectos`、`hotcrm`、`mobile`、`www.objectos.ai`;未来新仓默认此类。 - 单车道仓 `repo:*` 席自理机械三务,⛔ 不产 `domain:*`;决策卡入本仓收件箱,不落 objectstack。 - 机械三务 = 自扫 sweep、自打 `type`、自做首触(含 `finding`;业务理由归召唤的总监席)。 - 新仓登记是一张清单:座位贴、标签、类别归属、门禁盘点、写身份锁移植(deny + hooks)。 diff --git a/.claude/skills/pm-dispatch/references/lanes/mobile.md b/.claude/skills/pm-dispatch/references/lanes/mobile.md new file mode 100644 index 00000000000..bbae1c782be --- /dev/null +++ b/.claude/skills/pm-dispatch/references/lanes/mobile.md @@ -0,0 +1,49 @@ +# 车道岗位说明:repo:mobile + +见 cross-repo-coordination.md;本文是本席的岗位说明,现值状态恒在座位贴,⛔ 不迁入本文件。 + +## 形态 + +- 本席为姊妹仓执行座位:在 mobile 仓认领、派发、复核、落地。 +- 按需召唤:维护者以指令行 `pm-dispatch mobile` 召唤;本席不建巡查 routine,队列清空即退席。 +- ⛔ 不产 `domain:*`;机械三务(含首触定级)按 cross-repo-coordination.md 单车道仓条自理。 + +## 范围 + +- `objectstack-ai/mobile` 全仓:Expo 原生壳,在 WebView 中宿主平台 Console。 +- 边界:业务界面与元数据渲染恒在平台 `ui/` 实现。 +- ⛔ 永不在壳内原生重写 Console 已有的界面。 +- 壳只收原生能力:服务器选择、推送、桥接方法、系统集成、原生加载与兜底页。 +- 原生业务页只经仓内 `docs/HYBRID-SHELL.md` 的路由归属规则进入,该节四条前提缺一不收。 +- 移动端发现的 Console 缺陷,立普通平台卡到 objectstack(渲染器在其 `ui/`),待分诊。 +- 那是 file-at-destination、非缝卡;mobile 侧同笔挂 `pm:blocked` 加 `Blocked-by:` 回链。 +- ⛔ 永不在壳内绕行 Console 缺陷:绕行把平台缺口藏进壳,其余宿主从此拿不到修复。 +- 桥接契约单源在仓内 `docs/HYBRID-SHELL.md`。 +- 新桥接方法验收后,即在 objectstack 立 Console 消费卡。 +- mobile 自己的卡(含决策卡)都住 mobile 仓:issue 住在修复落地的仓,决策入本仓收件箱。 +- 无 `repo:mobile` 缝标签:今无具名读者。 +- 首张跨仓次序即实质的协调卡出现时,随该卡走词表 PR 增设。 + +## 常设承诺 + +- 半状态巡查在本仓无载体:无 `half-state-patrol.yml`,无 workflow 即无锚 issue。 +- ⇒ 手工半边:开新派发前整车道全交集读 open 卡。 +- 逐张核交付 PR 是否已合并或关闭,先处置半状态;⛔ 无锚不等于免检。 +- 壳不持 API 凭据、不调平台 API;⛔ 不重新引入 `@objectstack/*` 客户端依赖。 +- `main` 上的 push 会跑 `eas-build.yml` 与 `eas-update.yml`(配置了 `EXPO_TOKEN` 时),等同发布动作。 +- ⇒ 二者仍由 push 触发期间,本仓 PR 的合并恒归维护者(AGENTS.md 发布条)。 +- 二者改为手动触发后,上条解除。 +- 设备验证无 CI 载体:需真机的验收项写进 PR `## 维护者速读` 的「需要你做的」。 +- ⛔ 未上真机的项不报已验。 +- 本仓有 `.changeset/` 而无 changeset 门禁:用户可见变更随 PR 带 changeset,席位复核时核对。 +- 不扩散需求:创业阶段聚焦原则全额适用;原生能力卡第一问恒为 Web 是否真做不到。 +- 框架单源在 SKILL.md 〈升级与决策〉,⛔ 不另抄。 +- pm 状态机词表各仓统一,幂等创建在 `scripts/pm/ensure-pm-labels.sh`,对 mobile 实跑是落地步骤。 + +## 席内判断 + +- 收卡第一问:原生能力还是业务界面。 +- 业务界面 ⇒ 转 objectstack 平台卡,本卡关 not planned 并回链。 +- 原生页面化提案进决策箱,附该路由的移动端用量与 Web 端性能读数;无读数不收。 +- 会话转移、桥接新增写能力、导航策略放行新来源,皆属安全边界,恒在人工地板。 +- 拿不准升决策箱,⛔ 不自裁。 diff --git a/.claude/skills/pm-dispatch/references/project-forms.md b/.claude/skills/pm-dispatch/references/project-forms.md index 1e3655b9c43..216398afe6d 100644 --- a/.claude/skills/pm-dispatch/references/project-forms.md +++ b/.claude/skills/pm-dispatch/references/project-forms.md @@ -13,7 +13,7 @@ - 项目指令只有一行:`pm-dispatch <席位> [<席位>…]`,如 `pm-dispatch 总监`、`pm-dispatch ui skills`。 - 首词恒为技能目录名 `pm-dispatch`;⛔ 不用 `fleet`,它已是 bot 与中继的名字。 - 席位词 = 中文名或车道文件名:总监 = `lanes/director.md`,分诊 = `lanes/triage.md`。 -- 其余席位词同 `lanes/.md` 文件名:ui、skills、devx、server、spec、hotcrm。 +- 其余席位词同 `lanes/.md` 文件名:ui、skills、devx、server、spec、hotcrm、mobile。 - 一车道多席:协调者取 🟢 行写本账号的那一席;无则取空席;再无则问维护者一次。 - 其余一切住本文:⛔ 不往项目里贴模板;⛔ 不在账号层复制技能。 diff --git a/scripts/pm/check-governed-merges.mjs b/scripts/pm/check-governed-merges.mjs index c8fc32ab754..e1806768b85 100644 --- a/scripts/pm/check-governed-merges.mjs +++ b/scripts/pm/check-governed-merges.mjs @@ -3,7 +3,7 @@ /** * check-governed-merges — report-only post-merge audit of the governed - * surfaces (#9495), across the five governed repos (#9619, #14867), plus the + * surfaces (#9495), across the six governed repos (#9619, #14867, mobile), plus the * pre-arm `--test` predicate every seat runs before flipping ready (#9550). * Enumerates the PRs that MERGED into `main` since a given date/ref whose diff * touched a governed surface — and, since #19036, every landing over @@ -13,7 +13,7 @@ * completed sweep exits 0 whether it found 0 or 40 entries; non-zero exits * classify the ENVIRONMENT, not the tree). * - * node scripts/pm/check-governed-merges.mjs # sweep, last 24h, all five repos + * node scripts/pm/check-governed-merges.mjs # sweep, last 24h, all six repos * node scripts/pm/check-governed-merges.mjs --since 7d # or 36h, or ISO date * node scripts/pm/check-governed-merges.mjs --since-ref v5.0.0-rc.3 # topological, exact * node scripts/pm/check-governed-merges.mjs --since-ref objectstack= --since-ref objectui= @@ -1400,9 +1400,13 @@ export function applyGeneratedExceptions(verdict, provenanceByPath = new Map()) } /** - * The five governed repos: the four the 2026-08-18 cross-repo extension named, + * The six governed repos: the four the 2026-08-18 cross-repo extension named, * plus `hotcrm`, added by the 2026-09-03 ruling on #14867 (「其他同意」 → 纳入) - * because the definition's own terms already covered it. `id` doubles as + * because the definition's own terms already covered it, plus `mobile`, the + * native shell that hosts the Console, registered as an on-demand repo lane + * by the maintainer's 2026-11-02 choice "Register, seat on demand + * (Recommended)". Its workflows stay outside the scoped `workflows` row, as + * hotcrm's do. `id` doubles as * the sibling directory name beside this checkout — the layout every session * container uses — and `--repo-root =` overrides it for any other * layout. A checkout whose `origin` remote is not `slug` is treated as ABSENT @@ -1414,6 +1418,7 @@ export const GOVERNED_REPOS = Object.freeze([ Object.freeze({ id: 'cloud', slug: 'objectstack-ai/cloud', what: 'the cloud repo' }), Object.freeze({ id: 'objectos', slug: 'objectstack-ai/objectos', what: 'the objectos repo' }), Object.freeze({ id: 'hotcrm', slug: 'objectstack-ai/hotcrm', what: 'the hotcrm exemplar app repo (#14867, ruled 2026-09-03)' }), + Object.freeze({ id: 'mobile', slug: 'objectstack-ai/mobile', what: 'the mobile native shell repo that hosts the Console (on-demand repo lane, 2026-11-02)' }), ]); export const SELF_REPO_ID = 'objectstack'; @@ -4827,7 +4832,7 @@ async function selfTest() { // ── multi-repo scope (#9619) ────────────────────────────────────────────── battery('multi-repo scope (#9619)'); - assert('five-governed-repos-declared', GOVERNED_REPOS.map((r) => r.id).join(',') === 'objectstack,objectui,cloud,objectos,hotcrm', GOVERNED_REPOS.map((r) => r.id).join(',')); + assert('six-governed-repos-declared', GOVERNED_REPOS.map((r) => r.id).join(',') === 'objectstack,objectui,cloud,objectos,hotcrm,mobile', GOVERNED_REPOS.map((r) => r.id).join(',')); // #14867: hotcrm pinned by SLUG as well as id. The defect this closes is not // a wrong row — it is NO row: an unconfigured repo prints nothing at all, so // a later removal would restore a silence indistinguishable from a clean @@ -4849,7 +4854,7 @@ async function selfTest() { }; const resolved = resolveRepoCheckouts({ selfRoot: '/w/objectstack', siblingDir: '/w', probe: (p) => layout[p] ?? { exists: false, slug: null } }); const byId = Object.fromEntries(resolved.map((r) => [r.id, r])); - assert('all-five-repos-are-resolved-not-just-the-self-repo', resolved.length === 5); + assert('all-six-repos-are-resolved-not-just-the-self-repo', resolved.length === 6); // /w/hotcrm is absent from the layout too, so this fixture also pins the // property #14867 bought: a governed repo with no checkout is UNAUDITED and // says so, where an unconfigured repo said nothing. diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index a25cee524cb..c1023157111 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -1456,6 +1456,11 @@ export const CEILINGS = new Map([ // ruling citations and incident narrative left; every rule stayed. Landed count, // headroom 0, same convention (lowering is always legitimate). ['.claude/skills/pm-dispatch/references/lanes/hotcrm.md', 53], + // repo:mobile lane charter — the on-demand seat for the native shell that + // hosts the Console (maintainer choice 2026-11-02, verbatim: "Register, seat + // on demand (Recommended)"). A NEW file, so this is an added row and no other + // row moves; set at the landed line count (headroom 0, same convention). + ['.claude/skills/pm-dispatch/references/lanes/mobile.md', 49], // Project Director seat charter (maintainer ruling 2026-08-27, verbatim: // 「项目总监 由人工定期指挥,负责处理 contract-review 类别的和需要决裁的。」; the file // carries it as a rule line since the rules-only rewrite, not as this quotation) @@ -2290,6 +2295,7 @@ export const MAX_TABLE_ROW_BYTES = new Map([ ['.claude/skills/pm-dispatch/references/lanes/spec.md', 0], ['.claude/skills/pm-dispatch/references/lanes/ui.md', 0], ['.claude/skills/pm-dispatch/references/lanes/hotcrm.md', 0], + ['.claude/skills/pm-dispatch/references/lanes/mobile.md', 0], ['.claude/skills/pm-dispatch/references/lanes/director.md', 0], ['.claude/skills/pm-dispatch/references/lanes/triage.md', 0], ['.claude/agents/os-dev.md', 0], diff --git a/scripts/pm/ensure-pm-labels.sh b/scripts/pm/ensure-pm-labels.sh index 7ed3b6f63e5..b3c32b34c33 100644 --- a/scripts/pm/ensure-pm-labels.sh +++ b/scripts/pm/ensure-pm-labels.sh @@ -183,7 +183,14 @@ gh() { # board unless one is later ruled). Those absences are deliberate, not oversights. # Actually RUNNING this against hotcrm is a PM landing step, same as objectos # (needs label-write credentials on that repo). -for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud objectstack-ai/objectos objectstack-ai/hotcrm; do +# +# mobile enrolled on the same terms when its on-demand repo lane was registered +# (maintainer choice 2026-11-02, verbatim: "Register, seat on demand +# (Recommended)"): the native shell that hosts the Console. Full pm vocabulary, +# OUT of the domain-lane loop and OUT of the target: loop, and no +# repo:mobile seam row until a seam card gives one a reader. Running this +# against mobile is a PM landing step, same as hotcrm. +for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud objectstack-ai/objectos objectstack-ai/hotcrm objectstack-ai/mobile; do gh label create pm:queue -R "$R" -c 0e8a16 -d "Ready for the PM dispatch loop" 2>/dev/null || true gh label create pm:dispatched -R "$R" -c 1d76db -d "Dispatched to a dev agent by /pm-dispatch" 2>/dev/null || true # needs-user-decision on a PR means awaiting the maintainer's review (SKILL.md 复核, 终局四件套); on a card it is the ruling inbox. From 33e1e9cdf374b923bdad3c67bb0a98dcd4277f1a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 06:54:16 +0000 Subject: [PATCH 2/5] pm-dispatch: address the contract review of the mobile lane registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - M1: the on-demand seat is now an exception the standing rules name — SKILL.md (project-seat wake rule, resident seats), project-forms.md (taking a seat builds the patrol), seat-lifecycle.md (empty queue is standby) — and the charter exits by SKILL.md's four-part self-exit, opening and closing its mailbox per summons - S1: the seat's window ends at ACCEPT plus hand-off; mobile merges stay the maintainer's - S2: Console-defect cards unblock on a released platform version the configured server can reach, not on an upstream merge - S3: the seat is not summoned before the shell rewrite is on mobile main - S4: the seat post lives in mobile; pm:seat is created there and fleet-roster's DEFAULT_REPOS lists mobile - S5: eas-submit.yml named; the release rule no longer conditions on a secret a seat cannot read, and workflow PRs stay maintainer-merged - S7: mobile joins the dependency direction and the app-repo list - S8: roster comments that state the current count say six; hotcrm's charter says 各仓统一 Claude-Session: https://claude.ai/code/session_01Q4EjjRHkJgnuLkU9vVgHHR Co-authored-by: Claude --- .claude/skills/pm-dispatch/SKILL.md | 4 +-- .../references/cross-repo-coordination.md | 2 +- .../references/decision-analysis.md | 2 +- .../pm-dispatch/references/lanes/hotcrm.md | 2 +- .../pm-dispatch/references/lanes/mobile.md | 16 +++++++--- .../pm-dispatch/references/project-forms.md | 2 +- .../pm-dispatch/references/seat-lifecycle.md | 2 +- scripts/pm/check-governed-merges.mjs | 14 ++++---- scripts/pm/check-skill-line-ratchet.mjs | 2 +- scripts/pm/ensure-pm-labels.sh | 32 +++++++++++-------- scripts/pm/fleet-roster.mjs | 4 +-- 11 files changed, 47 insertions(+), 35 deletions(-) diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index d4e41d2fbbb..ef20cc4a363 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -69,10 +69,10 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 批 = 一个上下文里读完的 ≤5 张同族卡,是质量单位,⛔ 不是预算。 - 班 = 一个会话的任期,只以交接或惰性回收结束。 - 席位两形:Routine 席与项目席(会话是车队项目的线程);细则见 `references/seat-lifecycle.md`。 -- 项目席唤醒 = PR 订阅 + 每席一个自建自绑巡查 routine(总监席除外);⛔ 无 `send_later` 链。 +- 项目席唤醒 = PR 订阅 + 自建自绑巡查 routine(总监席与按需席除外);⛔ 无 `send_later` 链。 - 探针先行:fire 的第一动作是一次最便宜的车道盘点查询,⛔ 在它之前不读任何长文本。 - 队列空(逐卡表见 `references/seat-lifecycle.md`)+ 无在飞 + 无待复核 + 决策箱无新答复 ⇒ 自退。 -- 分诊席与车道席常驻,断粮即换账号重开该席与信箱;分诊席默认判断档;裁决归总监席。 +- 分诊席与车道席常驻(按需席除外),断粮换号重开席与信箱;分诊默认判断档;裁决归总监。 - 子代理裁决逐份过转录核验采信。 ## 阶段细则索引 diff --git a/.claude/skills/pm-dispatch/references/cross-repo-coordination.md b/.claude/skills/pm-dispatch/references/cross-repo-coordination.md index 567798ee429..a1d5c1ec143 100644 --- a/.claude/skills/pm-dispatch/references/cross-repo-coordination.md +++ b/.claude/skills/pm-dispatch/references/cross-repo-coordination.md @@ -1,6 +1,6 @@ # 多仓协调 -- 产品依赖方向固定:`objectstack`(后端与 `ui/` 前端,`packages/spec` 唯一契约)→ `cloud`、`hotcrm`。 +- 依赖方向固定:`objectstack`(后端与 `ui/`,`packages/spec` 唯一契约)→ `cloud`、`hotcrm`、`mobile`。 - 多车道仓 `objectstack`:中央分诊唯一生产 `domain:*`/type/定级,定级例外见 triage-duties 自分诊。 - 单车道仓 `cloud`、`objectos`、`hotcrm`、`mobile`、`www.objectos.ai`;未来新仓默认此类。 - 单车道仓 `repo:*` 席自理机械三务,⛔ 不产 `domain:*`;决策卡入本仓收件箱,不落 objectstack。 diff --git a/.claude/skills/pm-dispatch/references/decision-analysis.md b/.claude/skills/pm-dispatch/references/decision-analysis.md index 3dbca4b56c2..1e8d2e6f014 100644 --- a/.claude/skills/pm-dispatch/references/decision-analysis.md +++ b/.claude/skills/pm-dispatch/references/decision-analysis.md @@ -43,7 +43,7 @@ ## 应用仓推荐序特例 -- 能力先建在平台(spec、objectstack 运行时与其 `ui/` 渲染器);应用仓(cloud、hotcrm)不自建替代。 +- 能力先建在平台(spec、运行时与 `ui/` 渲染器);应用仓(cloud、hotcrm、mobile)不自建替代。 - 阻塞源是平台缺陷 ⇒ 恒荐等待;⛔ 不荐绕行(形状容错、复刻平台规则)、不荐劈半落地。 - 过渡唯维护者明裁;应用仓临时扩展平台契约,仅当平台卡与移除卡同一裁决立出。 - 应用仓裁决立出的平台卡取被裁卡优先级,⛔ 不降档。推论出处:cloud 2932 A、cloud 2924 A。 diff --git a/.claude/skills/pm-dispatch/references/lanes/hotcrm.md b/.claude/skills/pm-dispatch/references/lanes/hotcrm.md index 7d825b6b09c..bc5aba187c9 100644 --- a/.claude/skills/pm-dispatch/references/lanes/hotcrm.md +++ b/.claude/skills/pm-dispatch/references/lanes/hotcrm.md @@ -43,7 +43,7 @@ - 依赖是已发布的 `@objectstack/*` 包,逐包定版号,非 git pin。 - ⇒ 平台侧修复必须先发版、再在此升版号才到得了展品。 - 上游卡对本道的解锁判据是已发布,不是已合并。 -- pm 状态机词表五仓统一,幂等创建在 `scripts/pm/ensure-pm-labels.sh`,对 hotcrm 实跑是落地步骤。 +- pm 状态机词表各仓统一,幂等创建在 `scripts/pm/ensure-pm-labels.sh`,对 hotcrm 实跑是落地步骤。 ## 席内判断 diff --git a/.claude/skills/pm-dispatch/references/lanes/mobile.md b/.claude/skills/pm-dispatch/references/lanes/mobile.md index bbae1c782be..d186fe0bc1c 100644 --- a/.claude/skills/pm-dispatch/references/lanes/mobile.md +++ b/.claude/skills/pm-dispatch/references/lanes/mobile.md @@ -4,8 +4,12 @@ ## 形态 -- 本席为姊妹仓执行座位:在 mobile 仓认领、派发、复核、落地。 -- 按需召唤:维护者以指令行 `pm-dispatch mobile` 召唤;本席不建巡查 routine,队列清空即退席。 +- 本席为姊妹仓执行座位:在 mobile 仓认领、派发、复核;落地窗口止于 ACCEPT 加交棒。 +- 按需席:维护者以指令行 `pm-dispatch mobile` 召唤;本席不建巡查 routine。 +- 退席按 SKILL.md 自退四件(队列空、无在飞、无待复核、决策箱无新答复)。 +- 信箱随召唤开、随退席关。 +- 前提:mobile 仓的原生壳改造已进其 `main`;之前 ⛔ 不召唤本席。 +- 座位贴住 mobile 仓,带 `pm:seat`;车队总表经 `fleet-roster.mjs` 默认仓列读到它。 - ⛔ 不产 `domain:*`;机械三务(含首触定级)按 cross-repo-coordination.md 单车道仓条自理。 ## 范围 @@ -17,6 +21,7 @@ - 原生业务页只经仓内 `docs/HYBRID-SHELL.md` 的路由归属规则进入,该节四条前提缺一不收。 - 移动端发现的 Console 缺陷,立普通平台卡到 objectstack(渲染器在其 `ui/`),待分诊。 - 那是 file-at-destination、非缝卡;mobile 侧同笔挂 `pm:blocked` 加 `Blocked-by:` 回链。 +- 解锁判据是修复已进平台发行版、配置的服务器可升到它;⛔ 不是上游已合并。 - ⛔ 永不在壳内绕行 Console 缺陷:绕行把平台缺口藏进壳,其余宿主从此拿不到修复。 - 桥接契约单源在仓内 `docs/HYBRID-SHELL.md`。 - 新桥接方法验收后,即在 objectstack 立 Console 消费卡。 @@ -30,9 +35,10 @@ - ⇒ 手工半边:开新派发前整车道全交集读 open 卡。 - 逐张核交付 PR 是否已合并或关闭,先处置半状态;⛔ 无锚不等于免检。 - 壳不持 API 凭据、不调平台 API;⛔ 不重新引入 `@objectstack/*` 客户端依赖。 -- `main` 上的 push 会跑 `eas-build.yml` 与 `eas-update.yml`(配置了 `EXPO_TOKEN` 时),等同发布动作。 -- ⇒ 二者仍由 push 触发期间,本仓 PR 的合并恒归维护者(AGENTS.md 发布条)。 -- 二者改为手动触发后,上条解除。 +- `main` 上的 push 跑 `eas-build.yml` 与 `eas-update.yml`;`eas-submit.yml` 手动触发即商店提交。 +- 三者皆按发布动作对待(AGENTS.md 发布条),⛔ 不由席位触发。 +- `EXPO_TOKEN` 是否配置席位读不到,恒按已配置。 +- ⇒ 本仓 PR 的合并恒归维护者;改 `.github/workflows/**` 的 PR 同此,不因触发方式改变而解除。 - 设备验证无 CI 载体:需真机的验收项写进 PR `## 维护者速读` 的「需要你做的」。 - ⛔ 未上真机的项不报已验。 - 本仓有 `.changeset/` 而无 changeset 门禁:用户可见变更随 PR 带 changeset,席位复核时核对。 diff --git a/.claude/skills/pm-dispatch/references/project-forms.md b/.claude/skills/pm-dispatch/references/project-forms.md index 216398afe6d..1a42aeec471 100644 --- a/.claude/skills/pm-dispatch/references/project-forms.md +++ b/.claude/skills/pm-dispatch/references/project-forms.md @@ -23,7 +23,7 @@ - 指令行就是指派:维护者在项目里写下或改写这一行,是唯一的指派动作。 - 项目聊天里的长句(「本账户坐 X;Y 的 PR 由本账户复审」)是等价写法。 - 坐席即把本账号写进 🟢 行、每席开一条席位线程;⛔ 无花名册文件。 -- 坐席即建巡查 routine(见 `seat-lifecycle.md`);分诊席加每小时裸卡轮;总监席不建。 +- 坐席即建巡查 routine(见 `seat-lifecycle.md`);分诊席加每小时裸卡轮;总监席与按需席不建。 ## 接管不等撞墙账号 diff --git a/.claude/skills/pm-dispatch/references/seat-lifecycle.md b/.claude/skills/pm-dispatch/references/seat-lifecycle.md index 6b7d87ac73d..35d93de4bcb 100644 --- a/.claude/skills/pm-dispatch/references/seat-lifecycle.md +++ b/.claude/skills/pm-dispatch/references/seat-lifecycle.md @@ -83,7 +83,7 @@ ## 停止条件与待命 - 停:队列空或 `rounds` 用尽(仅一次性调用适用);一轮 ≥ 半数派发失败或升级;维护者打断。 -- 队列空是待命非退场:巡查跑到收班,只维护者明令停;⛔ 不按「N 次无变化即停」的习惯。 +- 队列空是待命非退场(按需席除外):巡查跑到收班,只维护者令停;⛔ 不按 N 次无变化即停。 - 队列空是逐卡表非结论:报无卡可派(维护者/协调者/轮报)即列队列过滤当刻返回的各卡。 - 逐卡:卡号、同轮现读标签与 assignee(⛔ 不用缓存)、具名卡点;无卡点即候选,⛔ 不得报空。 - 卡点一份词表:候选定义反面(`execution-duties.md`),open `Blocked-by:`、无分诊审计、他席 `Claim:`。 diff --git a/scripts/pm/check-governed-merges.mjs b/scripts/pm/check-governed-merges.mjs index e1806768b85..830ada57b20 100644 --- a/scripts/pm/check-governed-merges.mjs +++ b/scripts/pm/check-governed-merges.mjs @@ -550,16 +550,16 @@ * The same day, asked whether the rule reaches the sibling repos — 「任何对 * agents.md 等文件的修改…包括 objectui cloud仓库」 — the maintainer answered * 「同意」. So the surface register above reaches every governed repository: - * by default each row governs all five — `objectstack`, `objectui`, `cloud`, - * `objectos` and `hotcrm` — and since the B2 ruling of 2026-10-13 (header + * by default each row governs all six — `objectstack`, `objectui`, `cloud`, + * `objectos`, `hotcrm` and `mobile` — and since the B2 ruling of 2026-10-13 (header * section "The register is scoped per row") a row may be scoped to a subset: * the `workflows` row names `objectstack`, `objectui` and `cloud`. This sweep - * still covers all five repos in one invocation, judging each against the + * still covers all six repos in one invocation, judging each against the * rows that govern it; `--test` and `--branch` answer for ONE repository, the * checkout at `--root` (`checkoutRepoFor`), and say which one on stderr. * * ⚠️ The 2026-08-18 quotation above names two sibling repos and the register - * below holds five, so read that quote as the repos IN VIEW that day — an + * below holds six, so read that quote as the repos IN VIEW that day — an * enumeration, never an exclusion, and never the register. The definition it * states (agent instruction files, judged the same across repos — still true * of every row that declares no `repos` scope) already covered `hotcrm`, a @@ -617,7 +617,7 @@ * asks whether the floor predates the window rather than whether the clone is * shallow, so a shallow container with enough depth — the common case, since * the default window is 24h — still sweeps exactly as before, with no fetch. - * Deepening is never done here: this sweep reads five checkouts it does not + * Deepening is never done here: this sweep reads six checkouts it does not * own, so the remedy is printed as a command for the operator to run. * * ## And a DEAD MIRROR is the same fact again, in the direction that reads as @@ -642,7 +642,7 @@ * 2026-08-30 `hotcrm` was probed BY HAND, as a control this sweep had no row * for — it was not configured here until the 2026-09-03 ruling above. The * reading stands as measured; what changed is that those four names are now - * four of the five repos this sweep audits itself.) Wherever that clone + * four of the six repos this sweep audits itself.) Wherever that clone * survives, this sweep * printed `✓ audited objectstack-ai/cloud — tip 15f55df2d ... 0 mainline * commit(s) in window` and exited 0 — and would have printed it FOREVER, since @@ -1997,7 +1997,7 @@ export const CALLER_DERIVED_NOTE = /** * `--pr`'s argument, as data. `16997` means this checkout's own repo; the * qualified spelling names any of the governed repos, because the PM audits - * five of them from one checkout — and since the register is scoped per row, + * six of them from one checkout — and since the register is scoped per row, * the repository named here is also the one the verdict answers for. Pure. */ export function parsePullTarget(value, selfSlug = null) { diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index c1023157111..849969a267e 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -1460,7 +1460,7 @@ export const CEILINGS = new Map([ // hosts the Console (maintainer choice 2026-11-02, verbatim: "Register, seat // on demand (Recommended)"). A NEW file, so this is an added row and no other // row moves; set at the landed line count (headroom 0, same convention). - ['.claude/skills/pm-dispatch/references/lanes/mobile.md', 49], + ['.claude/skills/pm-dispatch/references/lanes/mobile.md', 55], // Project Director seat charter (maintainer ruling 2026-08-27, verbatim: // 「项目总监 由人工定期指挥,负责处理 contract-review 类别的和需要决裁的。」; the file // carries it as a rule line since the rules-only rewrite, not as this quotation) diff --git a/scripts/pm/ensure-pm-labels.sh b/scripts/pm/ensure-pm-labels.sh index b3c32b34c33..62b3e230222 100644 --- a/scripts/pm/ensure-pm-labels.sh +++ b/scripts/pm/ensure-pm-labels.sh @@ -216,7 +216,7 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # the half-annotated shape) and H22's PM_RESIDUE_LABELS (a claim that an act # is still owed is residue on a closed card). Five-repo loop for the same # reason priority:p0 and pm:retriage are in it: the sweep is repo-parameterized - # (PM_SWEEP_REPO) and the state-model row requires the label in all five. + # (PM_SWEEP_REPO) and the state-model row requires the label in every repo of the loop. # Colour: needs-user-decision's family (a HUMAN owes something), one shade # lighter because the ruling here is already given. gh label create pm:awaiting-maintainer -R "$R" -c e99695 -d "Awaiting a manual maintainer action — ruling already given; no dispatch, no machine exit" 2>/dev/null || true @@ -227,8 +227,8 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # consumers: the lane pull order below (p0 > pm:blocking > target board > Bug # > the rest) and the half-state sweep's H10 (stale unclaimed p0) and H11 # (important card parked) in scripts/pm/check-half-states.mjs. It is in this - # five-repo loop because that sweep is repo-parameterized (PM_SWEEP_REPO) and - # grading is a five-repo triage duty — the same reasoning as pm:retriage + # per-repo loop because that sweep is repo-parameterized (PM_SWEEP_REPO) and + # grading is a per-repo triage duty — the same reasoning as pm:retriage # below. Measured 2026-08-20: objectui carries a live priority:p0 card whose # label OBJECT was auto-created by that first application, so it has GitHub's # default colour and an EMPTY description — exactly the drift this row closes @@ -245,15 +245,15 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # anchor by in whichever repo it is installed in, and it is an # H13_EXEMPT_LABELS member in scripts/pm/check-half-states.mjs, so it is # what stops the anchor itself from appearing as a finding in the very - # sweep it hosts. Same five-repo loop as priority:p0 above, on the rule + # sweep it hosts. Same per-repo loop as priority:p0 above, on the rule # stated beside it, quoted rather than paraphrased: "It is in this - # five-repo loop because that sweep is repo-parameterized (PM_SWEEP_REPO) - # and grading is a five-repo triage duty — the same reasoning as + # per-repo loop because that sweep is repo-parameterized (PM_SWEEP_REPO) + # and grading is a per-repo triage duty — the same reasoning as # pm:retriage below." For tracking the repo-parameterized sweep is # check-half-states.mjs's H13 check rather than triage grading, but the # test it applies is the same one: a label belongs in this loop when the # sweep reads it in every repo the sweep itself runs in, and H13 runs in - # all five. Measured 2026-09-03: objectstack and objectui both carry a + # every repo of the loop. Measured 2026-09-03: objectstack and objectui both carry a # live `tracking` object with GitHub's default colour `ededed` and an # empty description — the same drift the priority:p0 comment above # records for objectui. @@ -277,8 +277,8 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # question is unanswered, no dispatch) and the triage round's answer pass, # which answers what the objection comment asks each fire and drops the label # in the same write (SKILL.md 「`pm:retriage` 每 fire 先答异议评论所求,答后同笔 - # 摘标;须维护者答的进收件箱,标照摘」). It is in this five-repo loop because the - # state-model row requires the label to exist in all five; where a first + # 摘标;须维护者答的进收件箱,标照摘」). It is in this per-repo loop because the + # state-model row requires the label to exist in every repo of the loop; where a first # application already auto-created the object, creation here is a no-op and # `--reconcile` is what gives it this colour and description (measured # 2026-08-20: grey with an empty description in objectstack, and absent @@ -296,9 +296,9 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # first-touch close; and the census / half-state patrol, for which a tooling # card open in pm:queue with neither line is a half-state. (No fleet-wide # in-flight count: the take-order alone sequences tooling cards.) It is in this - # five-repo loop on the rule stated + # per-repo loop on the rule stated # beside priority:p0 above — the sweep that reads it is repo-parameterized - # (PM_SWEEP_REPO) and first-touch grading is a five-repo triage duty. Measured + # (PM_SWEEP_REPO) and first-touch grading is a per-repo triage duty. Measured # 2026-09-21 in objectstack, where the label is live on 44 queue cards: the # object is GitHub's default `ededed` with an EMPTY description, because until # this row nothing here named it — the exact drift the header describes, and @@ -313,7 +313,7 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # never merged and closed on account handover. Named consumers: every query # that enumerates open PRs for landing appends `-label:pm:mailbox` # (LEDGER_EXCLUSION, scripts/pm/mailbox-open.mjs, the one opener and closer), - # and a subscribed thread reads it as "owes no CI". In this five-repo loop + # and a subscribed thread reads it as "owes no CI". In this per-repo loop # because a lane project may keep its mailbox on any board it works. gh label create pm:mailbox -R "$R" -c c5def5 -d "A project's cross-account mailbox PR — never merged, owes no CI, excluded from every ledger" 2>/dev/null || true done @@ -484,6 +484,12 @@ gh label create repo:hotcrm -R objectstack-ai/objectstack -c fbca04 -d "Seam c # (measured 2026-08-20: the colour already matches; the description had drifted # to an older wording). gh label create pm:seat -R objectstack-ai/objectstack -c 1d76db -d "Seat registry post — protocol carrier, not dispatchable work; the label page is the fleet board" 2>/dev/null || true +# A sister-repo seat keeps its post in its own repository — hotcrm's posts +# live in hotcrm and fleet-roster.mjs reads that repo by default — so the +# "main repo only" sentence above holds for the domain:* lanes, not for repo +# lanes. mobile's charter (lanes/mobile.md) puts its seat post in mobile, so +# the label is created there too; fleet-roster's DEFAULT_REPOS lists mobile. +gh label create pm:seat -R objectstack-ai/mobile -c 1d76db -d "Seat registry post — protocol carrier, not dispatchable work; the label page is the fleet board" 2>/dev/null || true # Domain lanes — the roster lives in SKILL.md's domain table; keep both in sync # BY PR whenever a lane is added or retired. @@ -597,7 +603,7 @@ gh label create domain:ui -R objectstack-ai/objectui -c bfd4f2 -d "objectui ui l # docs/qa/platform-checklist/areas/*.json carries a top-level `axis` naming one # of these eleven values. # -# TWO repos, deliberately, and not the five-repo loop above: a feature point +# TWO repos, deliberately, and not the per-repo loop above: a feature point # spans 协议 → 运行时 → 前端, which is objectstack plus objectui. cloud is # parked (North Star "Not now"), objectos is the docs/site repo, and hotcrm is the # exemplar APP — its cards are app cards, and a platform gap found there is diff --git a/scripts/pm/fleet-roster.mjs b/scripts/pm/fleet-roster.mjs index eb4e4ea3760..4157224029f 100644 --- a/scripts/pm/fleet-roster.mjs +++ b/scripts/pm/fleet-roster.mjs @@ -139,7 +139,7 @@ export const EXIT_USAGE = 2; export const EXIT_PREREQUISITE = 3; export const EXIT_REFUSED = 4; -export const DEFAULT_REPOS = Object.freeze(['objectstack-ai/objectstack', 'objectstack-ai/objectui', 'objectstack-ai/hotcrm']); +export const DEFAULT_REPOS = Object.freeze(['objectstack-ai/objectstack', 'objectstack-ai/objectui', 'objectstack-ai/hotcrm', 'objectstack-ai/mobile']); export const DEFAULT_BOARD = 'objectstack-ai/objectstack'; export const ROSTER_LABEL = 'tracking'; export const ROSTER_MARKER = ''; @@ -683,7 +683,7 @@ async function selfTest() { battery('arguments: modes and every refusal'); const d = parseArgs([]); - t('defaults: the three repos, board objectstack, no write', [d.errors, d.repos, d.board, d.write], [[], [...DEFAULT_REPOS], DEFAULT_BOARD, null]); + t('defaults: the default repos, board objectstack, no write', [d.errors, d.repos, d.board, d.write], [[], [...DEFAULT_REPOS], DEFAULT_BOARD, null]); t('--repos splits on commas', parseArgs(['--repos', 'o/a, o/b']).repos, ['o/a', 'o/b']); t('a repo not shaped owner/name is refused', parseArgs(['--repos', 'nope']).errors.some((e) => e.includes('owner/name')), true); t('a repo named twice is refused', parseArgs(['--repos', 'o/a,o/a']).errors.some((e) => e.includes('twice')), true); From 41a35b30f7726cbd829af66361d798f4c46f3ddf Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 07:00:25 +0000 Subject: [PATCH 3/5] pm-dispatch: carry the delta review's should-fixes for the mobile lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - S9: the mobile seat stub records `Patrol: none — 按需席`, so the half-state sweep's H70 (which checks the line's presence, not its value) reads an on-demand seat honestly instead of flagging it - S10: project-forms.md defines 按需席 as a seat a charter sets on demand - S8 residue: the last "Five-repo loop" comment says per-repo Claude-Session: https://claude.ai/code/session_01Q4EjjRHkJgnuLkU9vVgHHR Co-authored-by: Claude --- .claude/skills/pm-dispatch/references/lanes/mobile.md | 1 + .claude/skills/pm-dispatch/references/project-forms.md | 2 +- scripts/pm/check-skill-line-ratchet.mjs | 2 +- scripts/pm/ensure-pm-labels.sh | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.claude/skills/pm-dispatch/references/lanes/mobile.md b/.claude/skills/pm-dispatch/references/lanes/mobile.md index d186fe0bc1c..8a52ec8e208 100644 --- a/.claude/skills/pm-dispatch/references/lanes/mobile.md +++ b/.claude/skills/pm-dispatch/references/lanes/mobile.md @@ -10,6 +10,7 @@ - 信箱随召唤开、随退席关。 - 前提:mobile 仓的原生壳改造已进其 `main`;之前 ⛔ 不召唤本席。 - 座位贴住 mobile 仓,带 `pm:seat`;车队总表经 `fleet-roster.mjs` 默认仓列读到它。 +- 存根的巡查行写 `Patrol: none — 按需席`:表明无 routine,半状态巡查只核此行在不在。 - ⛔ 不产 `domain:*`;机械三务(含首触定级)按 cross-repo-coordination.md 单车道仓条自理。 ## 范围 diff --git a/.claude/skills/pm-dispatch/references/project-forms.md b/.claude/skills/pm-dispatch/references/project-forms.md index 1a42aeec471..29289193dee 100644 --- a/.claude/skills/pm-dispatch/references/project-forms.md +++ b/.claude/skills/pm-dispatch/references/project-forms.md @@ -23,7 +23,7 @@ - 指令行就是指派:维护者在项目里写下或改写这一行,是唯一的指派动作。 - 项目聊天里的长句(「本账户坐 X;Y 的 PR 由本账户复审」)是等价写法。 - 坐席即把本账号写进 🟢 行、每席开一条席位线程;⛔ 无花名册文件。 -- 坐席即建巡查 routine(见 `seat-lifecycle.md`);分诊席加每小时裸卡轮;总监席与按需席不建。 +- 坐席即建巡查 routine(见 `seat-lifecycle.md`);分诊加每时裸卡轮;总监与宪章定的按需席不建。 ## 接管不等撞墙账号 diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index 849969a267e..79dbbb68e65 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -1460,7 +1460,7 @@ export const CEILINGS = new Map([ // hosts the Console (maintainer choice 2026-11-02, verbatim: "Register, seat // on demand (Recommended)"). A NEW file, so this is an added row and no other // row moves; set at the landed line count (headroom 0, same convention). - ['.claude/skills/pm-dispatch/references/lanes/mobile.md', 55], + ['.claude/skills/pm-dispatch/references/lanes/mobile.md', 56], // Project Director seat charter (maintainer ruling 2026-08-27, verbatim: // 「项目总监 由人工定期指挥,负责处理 contract-review 类别的和需要决裁的。」; the file // carries it as a rule line since the rules-only rewrite, not as this quotation) diff --git a/scripts/pm/ensure-pm-labels.sh b/scripts/pm/ensure-pm-labels.sh index 62b3e230222..22d46238f26 100644 --- a/scripts/pm/ensure-pm-labels.sh +++ b/scripts/pm/ensure-pm-labels.sh @@ -214,7 +214,7 @@ for R in objectstack-ai/objectstack objectstack-ai/objectui objectstack-ai/cloud # no machine exit ages out of sight unless a human is re-asked), H13's # PM_STATE_LABELS (a card in this state HAS a state, so it must not read as # the half-annotated shape) and H22's PM_RESIDUE_LABELS (a claim that an act - # is still owed is residue on a closed card). Five-repo loop for the same + # is still owed is residue on a closed card). Per-repo loop for the same # reason priority:p0 and pm:retriage are in it: the sweep is repo-parameterized # (PM_SWEEP_REPO) and the state-model row requires the label in every repo of the loop. # Colour: needs-user-decision's family (a HUMAN owes something), one shade From 93fb90c370cb93375ce26c2d86cdf9f5b364f4bb Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 07:06:46 +0000 Subject: [PATCH 4/5] pm-dispatch: create pm:seat in objectstack and mobile from one parsed line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check-label-desc-cap's self-test requires each parsed `gh label create` line to produce a distinct description; the second, identical pm:seat line for mobile broke "the run invokes at least one description per parsed line" (Lint · repo & tooling gates red on 33e1e9c and 41a35b3). One loop over both repos keeps the same labels with one parsed line. Claude-Session: https://claude.ai/code/session_01Q4EjjRHkJgnuLkU9vVgHHR Co-authored-by: Claude --- scripts/pm/ensure-pm-labels.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/pm/ensure-pm-labels.sh b/scripts/pm/ensure-pm-labels.sh index 22d46238f26..662020e132f 100644 --- a/scripts/pm/ensure-pm-labels.sh +++ b/scripts/pm/ensure-pm-labels.sh @@ -483,13 +483,16 @@ gh label create repo:hotcrm -R objectstack-ai/objectstack -c fbca04 -d "Seam c # object keeps its current colour and description until `--reconcile` runs # (measured 2026-08-20: the colour already matches; the description had drifted # to an older wording). -gh label create pm:seat -R objectstack-ai/objectstack -c 1d76db -d "Seat registry post — protocol carrier, not dispatchable work; the label page is the fleet board" 2>/dev/null || true # A sister-repo seat keeps its post in its own repository — hotcrm's posts # live in hotcrm and fleet-roster.mjs reads that repo by default — so the # "main repo only" sentence above holds for the domain:* lanes, not for repo # lanes. mobile's charter (lanes/mobile.md) puts its seat post in mobile, so -# the label is created there too; fleet-roster's DEFAULT_REPOS lists mobile. -gh label create pm:seat -R objectstack-ai/mobile -c 1d76db -d "Seat registry post — protocol carrier, not dispatchable work; the label page is the fleet board" 2>/dev/null || true +# the label is created there too (one invocation per repo, one parsed line — +# check-label-desc-cap measures distinct descriptions per line); fleet-roster's +# DEFAULT_REPOS lists mobile. +for R in objectstack-ai/objectstack objectstack-ai/mobile; do + gh label create pm:seat -R "$R" -c 1d76db -d "Seat registry post — protocol carrier, not dispatchable work; the label page is the fleet board" 2>/dev/null || true +done # Domain lanes — the roster lives in SKILL.md's domain table; keep both in sync # BY PR whenever a lane is added or retired. From 3ace75316f9e24bfda005ea0620cf35d1d4f663a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 07:44:02 +0000 Subject: [PATCH 5/5] =?UTF-8?q?pm-dispatch:=20allow=20rows=20for=20objects?= =?UTF-8?q?tack-ai/mobile=20=E2=80=94=20reads=20and=20PATCH=20only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maintainer ruling on the review's S6 (2026-11-02, verbatim choice: "A: reads + PATCH (Recommended)"): mobile gets the same per-repo REST rows hotcrm has for reads (issues, comments, labels, pulls, files, commits, check-runs), POST labels, and PATCH on pulls and issues — and deliberately NOT the ccr/ready_for_review and ccr/auto_merge pair, because every mobile merge is the maintainer's (lanes/mobile.md). The deny list is unchanged; check-settings-deny-roster stays green. Claude-Session: https://claude.ai/code/session_01Q4EjjRHkJgnuLkU9vVgHHR Co-authored-by: Claude --- .claude/settings.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.claude/settings.json b/.claude/settings.json index 8306ed86992..a15aaf86e77 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -30,33 +30,43 @@ "Bash(agent-browser skills *)", "Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/objectstack/issues/*/labels *)", "Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/hotcrm/issues/*/labels *)", + "Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/mobile/issues/*/labels *)", "Bash(curl -sS -X GET https://api.github.com/rate_limit *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues?* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues?* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues?* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/issues?* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues/* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues/* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues/* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/issues/* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues/*/comments* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues/*/comments* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues/*/comments* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/issues/*/comments* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/issues/*/labels* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/issues/*/labels* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/issues/*/labels* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/issues/*/labels* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/pulls/* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/pulls/* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/pulls/* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/files* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/pulls/*/files* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/files* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/pulls/*/files* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/commits* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/pulls/*/commits* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/commits* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/pulls/*/commits* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectstack/commits/*/check-runs* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/objectui/commits/*/check-runs* *)", "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/hotcrm/commits/*/check-runs* *)", + "Bash(curl -sS -X GET https://api.github.com/repos/objectstack-ai/mobile/commits/*/check-runs* *)", "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectstack/pulls/* *)", "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/hotcrm/pulls/* *)", + "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/mobile/pulls/* *)", "Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/ccr/ready_for_review *)", "Bash(curl -sS -X PUT https://api.github.com/repos/objectstack-ai/objectstack/pulls/*/ccr/auto_merge *)", "Bash(curl -sS -X POST https://api.github.com/repos/objectstack-ai/hotcrm/pulls/*/ccr/ready_for_review *)", @@ -74,7 +84,8 @@ "Bash(node scripts/pm/issue-transfer.mjs *)", "Bash(node --use-env-proxy scripts/pm/issue-transfer.mjs *)", "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/objectstack/issues/* *)", - "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/hotcrm/issues/* *)" + "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/hotcrm/issues/* *)", + "Bash(curl -sS -X PATCH https://api.github.com/repos/objectstack-ai/mobile/issues/* *)" ], "deny": [ "mcp__github__issue_write",