Skip to content

Commit 366391c

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/trusting-thompson-xvcx6q
# Conflicts: # packages/spec/liveness/translation.json
2 parents fc3257d + 6679644 commit 366391c

34 files changed

Lines changed: 1948 additions & 161 deletions
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
'@objectstack/mcp': patch
3+
'@objectstack/runtime': patch
4+
---
5+
6+
fix(mcp,runtime)!: the stateless `/api/v1/mcp` surface answers `GET` and `DELETE` with `405` and `Allow: POST`, so an MCP client stops re-opening a GET stream that ends at once
7+
8+
Clause-②: yes (narrowing)
9+
Metadata-protocol: none
10+
11+
<!-- adr-0087: not-required (no-migration-prescription) A transport verb answer on the MCP HTTP surface: no key of any metadata schema is removed, renamed or re-shaped, no export, type or error code is removed or renamed, and the 405 body is the MCP SDK transport's own. There is nothing for `objectstack migrate meta` to rewrite and no tombstone. -->
12+
13+
**BREAKING** accept-set narrowing at the MCP HTTP transport (`MCPServerRuntime.handleHttpRequest`, `@objectstack/mcp`), and on the standalone server's `/api/v1/mcp` route (`createDispatcherPlugin`, `@objectstack/runtime`).
14+
15+
- **Before.** The transport is stateless (no session id) and closes its per-request server when the request ends. A `GET` still reached the SDK's stream handler, which answered `200 text/event-stream` and then lost the stream when the server closed. An MCP client reads a GET stream that ends as a dropped connection and opens another one: claude-code re-opened it 2–3 times a second for as long as a session stayed connected. A `DELETE` answered `200` and ended nothing, because no session exists. Every other verb answered `405` with `Allow: GET, POST, DELETE`.
16+
- **Now.** Every verb but `POST` that reaches the transport (`OPTIONS` with CORS off; with CORS on the CORS middleware's `204` answers first on both doors) answers `405` with `Allow: POST` and the JSON-RPC body `{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}`, before a server is built. This is the Streamable HTTP transport's answer for a server that offers no GET stream and does not end sessions. The MCP SDK client treats a `405` on GET as "no stream offered" and does not retry it.
17+
- **The standalone server.** `createDispatcherPlugin` mounts `/api/v1/mcp` for `GET`, `POST` and `DELETE`, and now also declares it a path whose domain decides every verb (the declaration `/mcp/skill` and `/keys` already carry). Before, a `PUT`, a `PATCH` or an `OPTIONS` with CORS off matched no route there and the HTTP adapter answered it itself: `405` with `Allow: DELETE, GET, HEAD, POST` and a `METHOD_NOT_ALLOWED` envelope, to an anonymous caller too. Now those verbs reach the dispatcher like the mounted ones: an anonymous caller gets `401`, a signed-in one the transport's `405` with `Allow: POST`. A `createHonoApp` host already handed every verb to the dispatcher, so both doors now answer every verb alike.
18+
- **Unchanged.** `POST` (JSON-RPC: `initialize`, `tools/list`, `tools/call`, …) answers exactly as before. An anonymous caller is refused `401` before any verb answer, on every verb and on both doors.
19+
- **Who sees it.** A client that opens the GET stream on `/api/v1/mcp` now gets `405` instead of a `200` stream that ends at once. Nothing was ever sent on that stream. On the standalone server, an anonymous `PUT`, `PATCH` or `OPTIONS` (CORS off; with CORS on the CORS middleware's `204` answers `OPTIONS` first on both doors) on `/api/v1/mcp` now gets `401` instead of `405`.
20+
21+
**The remedy.** None needed for an MCP client: it stops opening the stream. A probe or health check that read `GET /api/v1/mcp` as `200` should send a `POST initialize` instead.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
fix(spec): the shipped liveness ledger cites the automation seam modules that now hold the moved engine bodies
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Seven rows in `liveness/connector.json`, `liveness/flow.json` and `liveness/translation.json` cited `AutomationEngine` methods in `service-automation/src/engine.ts` whose bodies now live in the service's seam modules, leaving one-hop wrappers behind. They now cite the body that holds the quoted code: `plugin-extension-api.ts#registerConnector`, `dag-traversal.ts#executeWithoutRetry`, `run-resume.ts#resumeInternal`, `plugin-extension-api.ts#deriveTriggerBinding` with the shared `flow-trigger-kind.ts#resolveFlowTriggerKind` (which is where `flow.type` is read now), and `node-text-rendering.ts#translatedFlowTemplate` / `#renderRefusalMessage`. The `translation` `flows.screens` row cites `i18n-resolver.ts#flowScreenCopyKey`, the file that spells its address, because the generic renderer it hands each slot to never names the key. That row is what turned `check:liveness` red.
11+
12+
What to do: nothing. No status, key or verdict changes; every row keeps its classification. Only the evidence pointers and the prose around them change.

‎.claude/skills/pm-dispatch/SKILL.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
111111
| `pm:blocking` | 有 open 下游依赖者(自 `Blocked-by:` 索引推导的缓存,⛔ 不手工挂);进选择全序 |
112112
| `pm:retriage` | 向分诊提问(改判、跨域 PR 指定车道、改路由、拆卡、裁 dev 报告留下的分叉),定车道与改路由限未派发卡,异议评论写明所求;与现行 `pm:*` 并存、⛔ 不摘原标;带本标签的 `pm:queue` 卡跳过派发 |
113113
| `finding` | 立卡三类内待首次定级,定级即离标;三类外关 not planned;不占队列不进收件箱 |
114-
| `tooling` | 修复落在门禁/脚本/workflow/技能/席位协议/PM 工具面而非产品包;分诊首触打,与 `domain:*` 同笔;三具名读者 = 候选查询排除、首触即关、普查半态行 |
114+
| `tooling` | 修复落在门禁/脚本/workflow/技能/席位协议/PM 工具面而非产品包;分诊首触打,与 `domain:*` 同笔;四具名读者 = 候选查询排除、每轮派发 ≤10%、首触即关、普查半态行 |
115115
| `target:<major>` | 发版阻塞:每个 backlog 恰好一个生产者 |
116116
| `pm:epic`(父单或 sub-issue) | 已由 epic PM 保留;其它 PM 永不取;⛔ 永不与 `pm:queue` 同挂 |
117117
| `pm:seat` | 座位登记贴:协议载体,不是待分诊的工作 |
@@ -195,10 +195,10 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
195195
- PR 上的标签 = 待维护者审阅,不入六态;与请审同为等人批清单,随获批或撤回判决离开。
196196
- 批准判定单源 = 队列守卫常量 `GOVERNED_APPROVERS`:授权账户 APPROVED 即算,⛔ 不卡 `commit_id`。
197197
- 批准后再推亦不过期;席位落地 = 过落地前检、清标、ready、auto-merge,踢出/变基同法。
198-
- ③ 请审是中继 op:`pr_create`/`pr_ready` 命中 Tier H 即向 `GOVERNED_APPROVERS` 全员请审。
199-
- 已请审/已指派/已评审者跳过(零写);PR 作者即其一时请审必 422,op 改为 assign 该账户替代。
200-
- 席位只核对 run 摘要 governed review 行,缺口才手补(免碰 draft 位 REST 路)并在轮次报告点名。
201-
- ready/draft 走中继 op;MCP 兜底已拒;端点见 rest-channel。
198+
- ③ 中继 `pr_create`/`pr_ready` 命中 Tier H 即向 `GOVERNED_APPROVERS` 中未请/派/审者请审。
199+
- 作者是审批人 ⇒ 指派它、请其余(请它必 422),否则请全员;速读只点非作者审批人去批。
200+
- 脱中继开的 PR 无 run 行:交速读前席位恒自读 `requested_reviewers`/`assignees`,⛔ 不只看 run 行。
201+
- 缺口经中继 `pr_request_reviewers`/`assign` 补,⛔ 不碰 draft 位;ACCEPT 与轮报点名脱中继作者。
202202
- ④ 轮次报告单列 awaiting a human merge。
203203
- skills 车道自有 PR:纯代码面如 `scripts/pm/` 由本席按达档自审(清单不减)后落地。
204204
- 受管面两层:Tier S = `.claude/**` 全树,余皆 Tier H 等人批;S 经达档复核 PASS 后 ready → 入队。

‎.claude/skills/pm-dispatch/references/cross-repo-coordination.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
分诊席每次 fire 路由与查重前读本文;执行席跨仓认领、派发或转移时读本文。
44

55
- 产品依赖方向固定:`objectstack`(后端,`packages/spec` 是唯一契约)→ `objectui`(前端)与 `cloud`。
6-
- objectui 构建产物经 `pnpm objectui:refresh` 回流。
76
- 多车道仓 `objectstack`、`objectui`:中央分诊是 `domain:*`/type/定级的唯一生产者。
87
- 单车道仓 `cloud`、`objectos`、`hotcrm`、`www.objectos.ai`;未来新仓默认此类。
98
- 单车道仓 `repo:*` 席自理机械三务,⛔ 不产 `domain:*`;决策卡入本仓收件箱,不落 objectstack。
@@ -26,8 +25,9 @@
2625
- 缝卡收窄为真协调卡:留 objectstack 带 `repo:*`,正文点名读者(哪个座位、哪一步)。
2726
- 决策卡留在立卡仓,总监席扫全部仓 `needs-user-decision` 呈批;在飞卡 ⛔ 不中途转仓。
2827
- 规则 2:跨层功能点或 objectui 消费的 `Seam:` 卡恒由分诊立父单 + 逐层子单,spec/后端先行。
28+
- `main` 有 `ui/` 起,新 spec 键不再先行、取代上句次序:与首个读者同 PR,hotcrm 读者同合并批。
2929
- 下游带 `Blocked-by: <owner/repo>#<n>`;`Blocked-by` 未关闭/未合并的不派发,对 GitHub 现验。
30-
- 被链接或同父的两单永不同批。
30+
- 被链接或同父的两单永不同批;`ui/` 起的新键与首个读者除外,⛔ `planned` 行不单独进 main。
3131
- pin 滞后是盲区:本仓 pin 是否已覆盖该 commit 是第二读数,派发前用 REST `compare` 核祖先。
3232
- 本地 `merge-base` 在浅检出上给假非祖先;未覆盖 ⇒ 派发令要求 PR 正文留档分叉窗口。
3333
- ⛔ pin bump 不做 rider:走专用 bump 脚本连带 override 与 lockfile。

‎.claude/skills/pm-dispatch/references/decision-analysis.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- 每批恰好 5 张,末批不足照呈;呈完即停等回批,⛔ 永不一条消息投多批。
88
- 批序:在飞被阻塞 > 运营阻塞 > 用户可见 > 结构性;卡面分析只一层 = 立卡席六项 + 四棱。
99
- 总监批前卡评论是增量:命令复核前提,逐棱同异,推荐/口径;不同意字母才展开四维。
10+
- 入批前认领:`Brief-claimed-by:` 行的写法、跳过与接管判据住 `lanes/director.md` 职责二。
1011
- 回批一行式逐卡对应字母选项;带的附加条件随执行落地,⛔ 不为它另起请示轮。
1112
- 呈递详解 = 逐卡散文按正文六项;⛔ 表格行、判词、栅格不构成详解,压缩批次是违规。
1213
- 受管草稿批例外:一 PR 一行(改了什么/为什么/席位意见/一个动作),⛔ 不套六项;速读住 PR。
@@ -43,7 +44,6 @@
4344

4445
## 应用仓推荐序特例
4546

46-
- 「平台相关的功能,应该尽量先改平台。」(维护者 2026-10-18 逐字,裁决台账 6245607810,批 362)
4747
- 能力先建在平台(spec、objectstack 运行时、objectui 渲染器);应用仓(cloud、hotcrm)不自建替代。
4848
- 阻塞源是平台缺陷 ⇒ 恒荐等待;⛔ 不荐绕行(形状容错、复刻平台规则)、不荐劈半落地。
4949
- 过渡唯维护者明裁;应用仓临时扩展平台契约,仅当平台卡与移除卡同一裁决立出。

‎.claude/skills/pm-dispatch/references/execution-duties.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- 整车道一次读全,本地求交:`list_issues` 带 `labels: [domain:X]` + 最小字段拿回全车道 open 集。
88
- 候选 = open、未 assign、无 `needs-user-decision`、无 `pm:retriage`;⛔ 排除三门皆无的 `tooling` 卡。
9+
- `tooling` 卡至多占一轮派发的 10%,溢出留积压、⛔ 不入 `pm:queue`;⛔ 无门禁无脚本强制。
910
- 无分诊审计评论的卡不是候选,预贴 `pm:queue` 视同无;例外一的 sub-issue 承父卡首触。
1011
- 已排队父单的 open sub-issue 自动是候选,`pm:epic` 父单的子树除外。
1112
- 每张候选读全文 + 全部评论,写派发词前做决策复读:评论读到最后一页。
@@ -56,7 +57,6 @@
5657

5758
- 归属 = session ID,⛔ 不认作者字段;`Account:` 派生自 assignee,不等即半态、持卡席下笔补正。
5859
- 卡 assignee 归 PM,dev 恒不写;PR assignee = 卡的,接管 ② 同笔换;读者 `is:pr is:open assignee:LOGIN`。
59-
- dev `pr_create` 带 `assignees: [LOGIN]`,同笔指派;席位自有 PR 指派自己。
6060
- 部分落地(PR 带 `Refs #N (item k)`,⛔ 不 `Fixes`)即释放:合入同笔回 `pm:queue` + 清 assignee。
6161
- 同笔 `Release:` 行点名已落项与余项去向;余项需换道/拆分加 `pm:retriage`,自队列重新认领。
6262
- 派发前按序执行原子对:① Assign @me,并把 `pm:dispatched` 与摘 `pm:queue` 放进同一次标签写入。
@@ -93,10 +93,10 @@
9393
- 下限档给机械卡(正确性由门禁农场机械判定)。
9494
- 默认判断档给 M/L、裁决实施与任何带设计判断的卡;拿不准就升一档。
9595
- 上限 = 契约复审档(`CONTRACT_REVIEW_TIER`),给最重协议/流程/编排卡,按卡取用非新默认。
96-
- 强制条款①:凡改协议语义面的卡一律契约复审档。
96+
- 强制条款①:凡改协议语义面或 `docs/adr/**` 的卡一律契约复审档;后者 effort 下限 `xhigh`。
9797
- 协议语义面 = 本 `SKILL.md`、决策框架拷贝所在文件、`.claude/agents/os-dev.md` 与 `skills/**`。
9898
- 仅 `references/**` 面、或治理面上一行级机械文本改动的卡,降为默认判断档施工。
99-
- 发布的 `skills/**` 整根随 `npx skills add` 发运,⛔ 无一行级豁免,逐行判机械不作数。
99+
- `skills/**`(随 `npx skills add` 发运)与 `docs/adr/**` ⛔ 无一行级豁免,逐行判机械不作数。
100100
- 纯机械一行 PM 酌定可至下限档;降档施工的补偿控制 = 复核席跑契约复审档。
101101
- 降档施工只经契约复审档复核到达维护者,⛔ 不新增标签不新增链。
102102
- 强制条款②:放宽接受集或扩大公开面的卡默认判断档施工;命中即 spec 车道的活。

‎.claude/skills/pm-dispatch/references/filing-gate.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# 立卡门与定级判据
22

3-
见 triage-duties.md 与 reading-discipline.md 的指针行。
4-
53
## 立卡门
64

75
> 出处,维护者 2026-09-21 逐字不译:刚才 os-sam 又被封号了,也是因为分诊批量处理issue的时候,所以现在 issue 太多对于车队是负担。 19546 我希望在创建issue 的环节就卡死,没必要的issue就不要创建。
@@ -16,6 +14,7 @@
1614
- 三种例外照立,要点首条「先测可达性」:可能泄露数据;发版固化的错误文字;维护者直派。
1715
- ② 只有维护者能做的决定,落卡即带「维护者速读」与四棱块。
1816
- ③ 维护者直派的任务,正文引其原话;④ 协调节点:跨仓/跨层父单与它的逐层子单。
17+
- 增改 pm 规则的卡只在维护者点名时立(归 ③,正文引点名原话);⛔ 席位自提不立。
1918
- ⛔ 不是卡:席位自己的失误、协议观察与「记住这条」,它们进座位贴或收班简报。
2019
- 「搭下个碰 X 的 PR」不算 `carrier:`;已落地工作欠的后续照立卡,⛔ 不按「不是卡」压下。
2120
- ⛔ 不是卡:丢卡重建(除非自身即 ①–④)、sweep 每 fire 重导的 pin/bump/卫生提醒。

‎.claude/skills/pm-dispatch/references/lanes/director.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525

2626
## 基本原则
2727

28-
- 三要素:每批 5 张;每卡从业务角度讲清问题、选项与代价;每卡带四维分析加一个推荐。
2928
- 聊天呈批逐卡六项,取材 = 卡面分析 + 本席增量;增量点名复核了什么,⛔ 不复述所同意的。
30-
- 一次裁清:子问题、分叉与执行参数(字母、车道、级别)同笔裁定,⛔ 不留 dev 另立决策卡。
3129

3230
## 职责一:契约复核记录事后审计与抽查(可选)
3331

@@ -49,6 +47,8 @@
4947

5048
- 首批读完前 ≤5 张同族卡即呈;⛔ 不先扫全箱;每张皆呈维护者,⛔ 无自裁、无免呈。
5149
- 取下五张只用便宜扫描:标签、assignee、PR 引用、速读首行;全文只读手上五张。
50+
- 入批前评论卡,首行 `Brief-claimed-by: session_<id> · batch #<n> · <UTC>`;只认会话 id,⛔ 不认账号。
51+
- 他会话该行未满 24h 即跳过,不呈不裁不改标;逾 24h 无 `Ruling:` 失效可再写;录裁/关卡即释。
5252
- 判据:开场标记→首批 ≤ 读五张;录裁只录维护者回字,⛔ 不自录、不自转工作态。
5353
- 决策收件箱 = 全部仓的 `needs-user-decision`,卡留立卡仓;⛔ 不复活已退役的汇总 issue。
5454
- 入箱勤务:校验/补全四棱块、速读与 `Prior rulings on this card:` 行;入箱同笔现读前提。

‎.claude/skills/pm-dispatch/references/lanes/ui.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
## 常设承诺
1919

20-
- 构建产物经 `pnpm objectui:refresh` 回流,见 cross-repo-coordination.md。
20+
- 构建产物经 `pnpm objectui:refresh` 回流,见 AGENTS.md。
2121
- 回流后的 console pin bump 是 objectstack 的单张卡,⛔ 永不做本仓 PR 的 rider。
2222
- `scripts/pm/**` 单写手恒在 objectstack 侧 ⇒ 本席的工具需求走上游卡带 `Blocked-by:` 回链。
2323
- 本仓标签/assignee 写走 objectstack `label-write.mjs --repo`,⛔ 不 MCP `issue_write`;被拒转有通道席。

‎.claude/skills/pm-dispatch/references/seat-lifecycle.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@
4242
- 收班 = 状态 flush + 在飞显式安置,不是在飞归零;派发口径失效,简报 ⛔ 不列作继承裁决。
4343
- 离任留守只写简报点名的项,⛔ 不读队列、不新派发、不碰未点名卡。
4444
- 换班报告默认零建议,只收三类:原则错/缺、可机械化项、平台事实变化。
45-
- 原则错/缺 → skills 席专题;可机械化项 → 门禁/脚本卡,⛔ 不是散文。
45+
- 原则错/缺 → 只进简报,维护者点名才立卡;可机械化项 → 门禁/脚本卡,⛔ 不是散文。
4646
- 平台事实变化 → references 事实表改一行。
47-
- 三类以 `finding` 入 skills 车道,首触归分诊席;三类之外默认关 not planned。
47+
- 后两类以 `finding` 入 skills 车道,首触归分诊席;三类之外默认关 not planned。
4848
- 接管/移交 = 改正文 + 审计评论(只作审计);收尾清单等细则见 `references/seat-post-protocol.md`。
4949
- epic 委托不入座位贴体系;新 `packages/spec` 工作恒归 spec 座位。
5050

@@ -68,7 +68,8 @@
6868

6969
- 每轮向维护者打中文轮次报告(chat 通道):issue → 判决 → PR 链接 → 备注的表。
7070
- 项目席轮报 = 卡线程清单,⛔ 不逐轮发聊天表;五项健康指标进总监席的每日摘要。
71-
- 报告加升级项、呈裁清单、awaiting a human merge 项、逐 PR 熔断命中项(无则 none)。
71+
- 报告加升级项、呈裁清单、逐 PR 熔断命中项(无则 none),与已落 PR 48h 内开出的跟进 PR 数。
72+
- 与产品提交占比:已合提交不触 `.claude/` `AGENTS.md` `scripts/pm` 门禁脚本 `.github/workflows` 者。
7273
- 报告含 `UNRECOGNISED` 行:对本轮门禁日志 grep `UNRECOGNISED` 逐行照录,`NOT APPLICABLE` 行也在内。
7374
- 健康指标五个:可派发库存(open `pm:queue` 未认领及趋势);决策箱(待维护者数)。
7475
- 决策箱指标还要点名带开放下游依赖的决策卡,从 `Blocked-by:` 反向索引现算。

0 commit comments

Comments
 (0)