Skip to content

Commit c62621f

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-4m2bvo
2 parents 4edb2de + 6679644 commit c62621f

10 files changed

Lines changed: 192 additions & 68 deletions

File tree

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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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/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/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/triage-duties.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
- ①只翻 report-only,不删门不跳测;②同笔送待决策汇总入下批,附两红 run;③不同意即翻回。
9494
- 条件:席位验收评论逐条核实、去重计数(候选/落地/已有/拒收)、一事一行、不计重排。
9595
- 机械边界测试(条款②判据):改动扩大接受集或公开面 ⇒ 是;拉回已声明契约 ⇒ 否。
96-
- 决策形状的卡一律入 `needs-user-decision`,带四棱块与推荐,由总监席按批呈维护者。
96+
- 决策形状的卡一律入 `needs-user-decision`,带四棱块与推荐;总监席认领见 `lanes/director.md`。
9797
- 轮次报告设呈裁清单专节(卡、推荐、所引权威),⛔ 无代裁清单、无追认表。
9898
- 回翻条款:实施中发现契约终究要动 ⇒ dev 停手,卡回决策箱,⛔ 永不静默重裁。
9999
- 请示纪律:方向性授权覆盖整条执行链一并做完,⛔ 不逐项回问。
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* [#25467 cut 11] The registry materialize/strip pair of
5+
* `ObjectStackProtocolImplementation` — the read exits' registry-side
6+
* convergence of a served object document (`materializeFromRegistry`), the
7+
* whole of what a `/meta` read exit owes an object document
8+
* (`governServedObject`), the write path's inverse of the registry seam
9+
* (`stripMaterializedFromRegistry`) and the whole of what the write path owes
10+
* the read (`stripServedObjectColumns`) — moved out of `protocol.ts` whole.
11+
*
12+
* A MOVE, not a redesign. Each function below is the body of the
13+
* `ObjectStackProtocolImplementation` method of the same name as it stood,
14+
* re-indented one level and otherwise unedited: the same reads, in the same
15+
* order, with the same `try`/`catch` fallbacks for partial registry doubles.
16+
*
17+
* ## How the moved bodies reach the class
18+
*
19+
* The shape #23050 set for `rest-server.ts` (its `data-action-routes.ts`
20+
* header carries the full reasoning), as `protocol-batch-data.ts` applies it.
21+
* The class keeps every method — the published `dist/*.d.ts` lists each one's
22+
* name, docblock and declared signature — and each body is one literal of
23+
* exactly the {@link RegistryMaterializeHost} members that method reads, plus
24+
* a `.call`. A method is handed over as a closure that calls it on the
25+
* protocol at call time, so a test double or spy set on the instance is still
26+
* the one the body reaches, and the moved bodies that call one another do so
27+
* through the protocol, exactly as before. Every other reader of these four
28+
* methods keeps calling the class method.
29+
*
30+
* The field the bodies read, `engine`, goes as a GETTER, so each read happens
31+
* when the body makes it: tests replace it on a constructed protocol.
32+
*
33+
* The module-level declarations of `protocol.ts` the bodies read stay there
34+
* and are imported from there: `canonicalMetaType`, which code that did not
35+
* move reads too, and `governServedItem` / `stripServedSystemColumns`, whose
36+
* docblocks the class's read and write paths cite by name. The module cycle is
37+
* evaluation-safe because every one of them is read only inside a function
38+
* body, never while the two modules are first evaluated. `index.ts` names what
39+
* it publishes from `protocol.ts` one by one, so the `export` the last two
40+
* gained for this keeps them off the published surface, and nothing
41+
* re-exports this module, so the published surface does not move.
42+
*/
43+
44+
import type { ObjectStackProtocolImplementation } from './protocol.js';
45+
import { canonicalMetaType, governServedItem, stripServedSystemColumns } from './protocol.js';
46+
47+
/**
48+
* The `ObjectStackProtocolImplementation` members the functions below read —
49+
* every one of them, and no other; each function's `this` is the `Pick` of the
50+
* members IT reads. Each is typed AS the class member (an indexed access on
51+
* the class), so a change to a member's signature on the class is a change
52+
* here too, and naming a member the class does not have is a compile error.
53+
* See the module header for which members are getters.
54+
*/
55+
export interface RegistryMaterializeHost {
56+
readonly engine: ObjectStackProtocolImplementation['engine'];
57+
materializeFromRegistry: ObjectStackProtocolImplementation['materializeFromRegistry'];
58+
stripMaterializedFromRegistry: ObjectStackProtocolImplementation['stripMaterializedFromRegistry'];
59+
}
60+
61+
/** The body of `ObjectStackProtocolImplementation#materializeFromRegistry`; the method's docblock there is its contract. */
62+
export function materializeFromRegistry<T>(
63+
this: Pick<RegistryMaterializeHost, 'engine'>,
64+
type: string, body: T): T {
65+
if (canonicalMetaType(type) !== 'object') return body;
66+
if (body === null || typeof body !== 'object') return body;
67+
const registry = (this.engine as any)?.registry;
68+
// Partial registry doubles in tests predate this method; a host that
69+
// cannot answer the gate answers exactly as it did before. The
70+
// `provisionSearchCompanionOnto` fallback keeps a double that was
71+
// written against #8038's narrower seam serving what it served then,
72+
// rather than silently losing the companion convergence to a rename.
73+
if (registry && typeof registry.materializeServedObjectOnto === 'function') {
74+
try {
75+
return registry.materializeServedObjectOnto(body) as T;
76+
} catch {
77+
// A read over an in-memory flag, the registry's own resolved
78+
// answer and the body's own fields; a failure here must not turn
79+
// a served schema into a 5xx.
80+
return body;
81+
}
82+
}
83+
if (registry && typeof registry.provisionSearchCompanionOnto === 'function') {
84+
try {
85+
return registry.provisionSearchCompanionOnto(body) as T;
86+
} catch {
87+
return body;
88+
}
89+
}
90+
return body;
91+
}
92+
93+
/** The body of `ObjectStackProtocolImplementation#governServedObject`; the method's docblock there is its contract. */
94+
export function governServedObject<T>(
95+
this: Pick<RegistryMaterializeHost, 'materializeFromRegistry'>,
96+
type: string, item: T): T {
97+
return this.materializeFromRegistry(type, governServedItem(type, item));
98+
}
99+
100+
/** The body of `ObjectStackProtocolImplementation#stripMaterializedFromRegistry`; the method's docblock there is its contract. */
101+
export function stripMaterializedFromRegistry<T>(
102+
this: Pick<RegistryMaterializeHost, 'engine'>,
103+
type: string, item: T): T {
104+
if (canonicalMetaType(type) !== 'object') return item;
105+
if (item === null || typeof item !== 'object') return item;
106+
const registry = (this.engine as any)?.registry;
107+
// Partial registry doubles in tests predate this method; the narrower
108+
// #8038 spelling keeps such a host stripping what it stripped before
109+
// rather than silently losing the companion strip to a rename.
110+
if (registry && typeof registry.stripMaterializedStampsFrom === 'function') {
111+
try {
112+
return registry.stripMaterializedStampsFrom(item) as T;
113+
} catch {
114+
// A read over the body's own fields; a failure here must not
115+
// turn a save into a 5xx.
116+
return item;
117+
}
118+
}
119+
if (registry && typeof registry.stripProvisionedSearchCompanionFrom === 'function') {
120+
try {
121+
return registry.stripProvisionedSearchCompanionFrom(item) as T;
122+
} catch {
123+
return item;
124+
}
125+
}
126+
return item;
127+
}
128+
129+
/** The body of `ObjectStackProtocolImplementation#stripServedObjectColumns`; the method's docblock there is its contract. */
130+
export function stripServedObjectColumns<T>(
131+
this: Pick<RegistryMaterializeHost, 'stripMaterializedFromRegistry'>,
132+
type: string, item: T): T {
133+
return this.stripMaterializedFromRegistry(type, stripServedSystemColumns(type, item));
134+
}

‎packages/metadata-protocol/src/protocol.ts‎

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,13 @@ import {
386386
isUnservedSealedOverlay,
387387
servedLockState,
388388
} from './protocol-lock-state.js';
389+
// [#25467 cut 11] The registry materialize/strip pair of the served object document.
390+
import {
391+
governServedObject,
392+
materializeFromRegistry,
393+
stripMaterializedFromRegistry,
394+
stripServedObjectColumns,
395+
} from './protocol-registry-materialize.js';
389396

390397
/**
391398
* Canonical Zod schema per metadata type lives in
@@ -560,7 +567,7 @@ function canonicalizeMetaRequestType<T extends { type: string }>(request: T): T
560567
* PUT round-trip would persist the injected columns into `sys_metadata`, and the
561568
* #4326 byte-identical invariant would break the day this shipped.
562569
*/
563-
function governServedItem<T>(type: string, item: T): T {
570+
export function governServedItem<T>(type: string, item: T): T {
564571
if (canonicalMetaType(type) !== 'object') return item;
565572
return applyInjectedSystemColumns(applyAuditFieldGovernance(item));
566573
}
@@ -583,7 +590,7 @@ function governServedItem<T>(type: string, item: T): T {
583590
* the platform's own definition, and a declared `owner_id` carrying the author's
584591
* own label survives untouched.
585592
*/
586-
function stripServedSystemColumns<T>(type: string, item: T): T {
593+
export function stripServedSystemColumns<T>(type: string, item: T): T {
587594
return canonicalMetaType(type) === 'object' ? stripInjectedSystemColumns(item) : item;
588595
}
589596

@@ -9069,32 +9076,12 @@ export class ObjectStackProtocolImplementation implements
90699076
* which is the majority path this converges the minority onto).
90709077
*/
90719078
private materializeFromRegistry<T>(type: string, body: T): T {
9072-
if (canonicalMetaType(type) !== 'object') return body;
9073-
if (body === null || typeof body !== 'object') return body;
9074-
const registry = (this.engine as any)?.registry;
9075-
// Partial registry doubles in tests predate this method; a host that
9076-
// cannot answer the gate answers exactly as it did before. The
9077-
// `provisionSearchCompanionOnto` fallback keeps a double that was
9078-
// written against #8038's narrower seam serving what it served then,
9079-
// rather than silently losing the companion convergence to a rename.
9080-
if (registry && typeof registry.materializeServedObjectOnto === 'function') {
9081-
try {
9082-
return registry.materializeServedObjectOnto(body) as T;
9083-
} catch {
9084-
// A read over an in-memory flag, the registry's own resolved
9085-
// answer and the body's own fields; a failure here must not turn
9086-
// a served schema into a 5xx.
9087-
return body;
9088-
}
9089-
}
9090-
if (registry && typeof registry.provisionSearchCompanionOnto === 'function') {
9091-
try {
9092-
return registry.provisionSearchCompanionOnto(body) as T;
9093-
} catch {
9094-
return body;
9095-
}
9096-
}
9097-
return body;
9079+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9080+
const readEngine = () => this.engine;
9081+
const host: ThisParameterType<typeof materializeFromRegistry> = {
9082+
get engine() { return readEngine(); },
9083+
};
9084+
return (materializeFromRegistry<T>).call(host, type, body);
90989085
}
90999086

91009087
/**
@@ -9107,7 +9094,11 @@ export class ObjectStackProtocolImplementation implements
91079094
* #7556's boundary).
91089095
*/
91099096
private governServedObject<T>(type: string, item: T): T {
9110-
return this.materializeFromRegistry(type, governServedItem(type, item));
9097+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9098+
const host: ThisParameterType<typeof governServedObject> = {
9099+
materializeFromRegistry: (...a) => this.materializeFromRegistry(...a),
9100+
};
9101+
return (governServedObject<T>).call(host, type, item);
91119102
}
91129103

91139104
/**
@@ -9132,29 +9123,12 @@ export class ObjectStackProtocolImplementation implements
91329123
* named stamp — the same reason {@link materializeFromRegistry} does.
91339124
*/
91349125
private stripMaterializedFromRegistry<T>(type: string, item: T): T {
9135-
if (canonicalMetaType(type) !== 'object') return item;
9136-
if (item === null || typeof item !== 'object') return item;
9137-
const registry = (this.engine as any)?.registry;
9138-
// Partial registry doubles in tests predate this method; the narrower
9139-
// #8038 spelling keeps such a host stripping what it stripped before
9140-
// rather than silently losing the companion strip to a rename.
9141-
if (registry && typeof registry.stripMaterializedStampsFrom === 'function') {
9142-
try {
9143-
return registry.stripMaterializedStampsFrom(item) as T;
9144-
} catch {
9145-
// A read over the body's own fields; a failure here must not
9146-
// turn a save into a 5xx.
9147-
return item;
9148-
}
9149-
}
9150-
if (registry && typeof registry.stripProvisionedSearchCompanionFrom === 'function') {
9151-
try {
9152-
return registry.stripProvisionedSearchCompanionFrom(item) as T;
9153-
} catch {
9154-
return item;
9155-
}
9156-
}
9157-
return item;
9126+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9127+
const readEngine = () => this.engine;
9128+
const host: ThisParameterType<typeof stripMaterializedFromRegistry> = {
9129+
get engine() { return readEngine(); },
9130+
};
9131+
return (stripMaterializedFromRegistry<T>).call(host, type, item);
91589132
}
91599133

91609134
/**
@@ -9163,7 +9137,11 @@ export class ObjectStackProtocolImplementation implements
91639137
* path owes {@link governServedObject}.
91649138
*/
91659139
private stripServedObjectColumns<T>(type: string, item: T): T {
9166-
return this.stripMaterializedFromRegistry(type, stripServedSystemColumns(type, item));
9140+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9141+
const host: ThisParameterType<typeof stripServedObjectColumns> = {
9142+
stripMaterializedFromRegistry: (...a) => this.stripMaterializedFromRegistry(...a),
9143+
};
9144+
return (stripServedObjectColumns<T>).call(host, type, item);
91679145
}
91689146

91699147
/**

0 commit comments

Comments
 (0)