从 #10888 分出,由 PM engine 席上报。这是 packages/spec 契约变更,需要维护者裁决;在裁定前 #10888 无法派发,本席不会在它上面建任何东西。
已测量的事实(#10886 的 face 清点产出,我按内容独立核过)
#10888 要 trim saveMetaItem 的 spec-validation 422 消息(它把结构化 issues[] 的内容又用散文复述了一遍)。trim 的前置条件是 declare-then-trim:先确认每个引用这条消息的 face 都有结构化通道,再删散文。
duplicatePackage 的 failed[].error 是唯一载体:
- 它在 200 上作为响应数据返回,不是错误包络;
- 数组是内联类型
{type, name, error},没有 issues 槽;
- ⭐
duplicatePackage 在 packages/spec/src/api/protocol.zod.ts 里出现 0 次 —— 它根本没有响应 schema。
所以在它上面声明结构化通道,是比 #10895 为 publishPackageDrafts 做的那次严格更大的工程:那次是给一个已声明的响应加字段,这次要从零建立一个门的响应契约。
⚠️ 顺带纠正一条容易被沿用的旧判断:#10895 的标题是「declare failed[].issues + seedApplied.issues」,看起来像是已经解决了这个封锁——没有,它声明的是 publishPackageDrafts 的 failed[],是另一个 face。
⭐ 一条会改变「声明什么」的发现:#11015
?force=true 这句补救措施被逐字引到 duplicatePackage 的 failed[].error 上,但 POST /packages/:id/duplicate 在 query 和 body 里都不接受 force,duplicatePackage 的请求类型里也没有这个字段。
也就是说:在这条消息唯一承载的那个 face 上,它承载的补救是不可执行的。 让这条消息「承重」的那个属性,恰恰在那里是坏的——这直接削弱了「不能 trim,因为消息在承重」这个论证里最强的一段。
⚠️ 所以本裁决不应只问「要不要声明」,还应先问「那个 face 上到底该说什么」。
选项
A. 给 duplicatePackage 建响应 schema,并在 failed[] 上声明 issues。 之后 #10888 的 trim 可以照 declare-then-trim 正常做。代价:新建一个门的响应契约,是本轮最大的一块 spec 面;收益是这个门从「无契约」变成「有契约」,而它今天在 200 上返回的失败数据是完全未声明的。
B. 先修 #11015,再重新评估。 既然那个 face 上的补救不可执行,也许正确的动作不是「声明结构化通道以便删散文」,而是先让那句话变成真的(给端点加 force,或把这句从该 face 拿掉)。修完之后 #10888 的载体分析要重做——可能结论就变了。
C. 维持现状。 #10888 长期停在 pm:queue,422 的散文重复保留。代价是重复真实存在且修法已知,只卡在声明上;好处是零 spec 面变更。
本席建议
B 先于 A。 理由是证据顺序而非偏好:A 的全部动机是「这条消息在那个 face 上承重、所以要先给它一个结构化替身」,而 #11015 表明它在那里承载的东西本身是错的。先按一个可能不该保留的内容去设计契约,是把错误固化进 spec。B 的成本远小于 A(一个端点的入参或一句话),做完之后 A 到底还要不要做、要声明什么,都会更清楚。
⛔ C 只值得写出来以便否掉:重复是真的,修法是已知的,卡的只是声明。
相关
从 #10888 分出,由 PM engine 席上报。这是
packages/spec契约变更,需要维护者裁决;在裁定前 #10888 无法派发,本席不会在它上面建任何东西。已测量的事实(#10886 的 face 清点产出,我按内容独立核过)
#10888 要 trim
saveMetaItem的 spec-validation 422 消息(它把结构化issues[]的内容又用散文复述了一遍)。trim 的前置条件是 declare-then-trim:先确认每个引用这条消息的 face 都有结构化通道,再删散文。duplicatePackage的failed[].error是唯一载体:{type, name, error},没有issues槽;duplicatePackage在packages/spec/src/api/protocol.zod.ts里出现 0 次 —— 它根本没有响应 schema。所以在它上面声明结构化通道,是比 #10895 为
publishPackageDrafts做的那次严格更大的工程:那次是给一个已声明的响应加字段,这次要从零建立一个门的响应契约。failed[].issues+seedApplied.issues」,看起来像是已经解决了这个封锁——没有,它声明的是publishPackageDrafts的failed[],是另一个 face。⭐ 一条会改变「声明什么」的发现:#11015
?force=true这句补救措施被逐字引到duplicatePackage的failed[].error上,但POST /packages/:id/duplicate在 query 和 body 里都不接受force,duplicatePackage的请求类型里也没有这个字段。也就是说:在这条消息唯一承载的那个 face 上,它承载的补救是不可执行的。 让这条消息「承重」的那个属性,恰恰在那里是坏的——这直接削弱了「不能 trim,因为消息在承重」这个论证里最强的一段。
选项
A. 给
duplicatePackage建响应 schema,并在failed[]上声明issues。 之后 #10888 的 trim 可以照 declare-then-trim 正常做。代价:新建一个门的响应契约,是本轮最大的一块 spec 面;收益是这个门从「无契约」变成「有契约」,而它今天在 200 上返回的失败数据是完全未声明的。B. 先修 #11015,再重新评估。 既然那个 face 上的补救不可执行,也许正确的动作不是「声明结构化通道以便删散文」,而是先让那句话变成真的(给端点加
force,或把这句从该 face 拿掉)。修完之后 #10888 的载体分析要重做——可能结论就变了。C. 维持现状。 #10888 长期停在
pm:queue,422 的散文重复保留。代价是重复真实存在且修法已知,只卡在声明上;好处是零 spec 面变更。本席建议
B 先于 A。 理由是证据顺序而非偏好:A 的全部动机是「这条消息在那个 face 上承重、所以要先给它一个结构化替身」,而 #11015 表明它在那里承载的东西本身是错的。先按一个可能不该保留的内容去设计契约,是把错误固化进 spec。B 的成本远小于 A(一个端点的入参或一句话),做完之后 A 到底还要不要做、要声明什么,都会更清楚。
⛔ C 只值得写出来以便否掉:重复是真的,修法是已知的,卡的只是声明。
相关
issues[]on the envelope, but message-only faces (duplicatePackagefailed[].error) forbid the #10524 trim until they declare a structured channel #10888(被封的 trim 卡)· saveMetaItem's DESTRUCTIVE_CHANGE 409 message inlines the same issue prose its structuredissuescarries — the remaining duplication of the #10524 family, different refusal class #10886 / PR Inventory the DESTRUCTIVE_CHANGE 409's wire faces, and pin the sole carrier that forbids the trim #11016(产出这份 face 清点,钉住了唯一载体)publishPackageDrafts做过同类声明——不同 face)POST /packages/:id/duplicatereports "re-submit with ?force=true to proceed" on a door that accepts noforce— the remedy names a mechanism unavailable on that face #11015(?force=true在该 face 上不可执行)· [finding]metadata-protocol's batch verbs still put caught error text on client-facing payloads — the 8 producers option C did not reach #8333(GUARD pin 形状)