Skip to content

Commit 3d66e79

Browse files
committed
Merge main into claude/project-thread-80dotk
main's #25796 rewrote the `translation/flows.screens` evidence to cite the seam modules, superseding the ledger hunk this branch carried from #25751; the conflict resolves to main's row, so this branch no longer touches the ledger. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X4d6XVfcfxL17bMpptytcc
2 parents 87ff23f + e2a4b6a commit 3d66e79

31 files changed

Lines changed: 1795 additions & 103 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: 1 addition & 1 deletion
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` | 座位登记贴:协议载体,不是待分诊的工作 |

‎.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/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/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:` 反向索引现算。

‎docs/adr/0019-app-as-consumer-unit.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
**Deciders**: ObjectStack Protocol Architects
66
**Builds on**: ADR-0003 (Package as First-Class Citizen), ADR-0006 (Three-Layer Tenancy), ADR-0016 (Studio Package Authoring & Publish)
77
**Consumers**: `@objectstack/spec/kernel` (`plugin.zod.ts`), `@objectstack/spec/cloud` (`marketplace.zod.ts`), the Console `marketplace` UI, the Studio publish flow, `docs/design/marketplace-publishing.md`
8+
**Related**: [ADR-0141](./0141-inter-app-dependency-declared-checked-before-install.md) (2026-10-25) — the separate, gated decision §Out of scope asks for on "Shared/published data model + inter-App dependencies", taken for the dependency half only (a declared `manifest.dependencies` entry plus a pre-install check; the shared data model half stays out of scope). Additive cross-reference under ADR-0130 D2's recording convention; this record's text is unchanged.
89

910
> **Revision history**
1011
> - **v1/v2** explored a much larger scheme: a metadata/code *plane* split,

0 commit comments

Comments
 (0)