Repository navigation
Closed
Labels
domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
Description
由 #7019 的区域测量顺带看到(PD #10 另立卡)。⛔ 不要捎带在能力门 PR 里改 —— 混进去会让那个 PR 的评审面失控。
三种形状(全部在 packages/rest/src/rest-server.ts,逐条实测)
| handler | 代码 | 信封 |
|---|---|---|
POST /meta/_migrate-stored |
:3765-3770 |
{ error: { code: 'FORBIDDEN', message } } —— 嵌套,符合 ADR-0112 |
DELETE /meta/:type/:name |
:4697 |
{ error: 'Reset operation not supported by protocol implementation' } —— 裸字符串,无 code |
PUT /meta/:type/:section/:name |
:4996 |
{ error: 'Save operation not supported by protocol implementation', code: 'NOT_IMPLEMENTED' } —— code 是兄弟键,不是嵌套 |
三个 handler 在同一个文件里,彼此相隔数百行,同属 /meta 前缀。
实测原文:
:4996 res.status(501).json({ error: 'Save operation not supported by protocol implementation', code: 'NOT_IMPLEMENTED' });
:4697 res.status(501).json({
error: 'Reset operation not supported by protocol implementation',
});
为什么这不只是「不好看」
对调用方而言,读 code 的客户端代码在这三条路由上要写三种取法:err.error.code、(取不到)、err.code。任何一种统一写法都会在另外两条上静默取到 undefined —— 而 undefined 走的是「没有 code」分支,不是报错分支。这正是 Prime Directive #12 说的「生产者即契约」被破坏的形状:消费者被迫用 ?? 容忍生产者的不一致。
分级建议:finding,今天没有用户会撞到
两条不合规的都是 501 分支 —— 只在 protocol 实现缺方法时才走到。出厂 protocol 实现两个方法都有,所以默认部署上这两个分支不可达。但它们是模板:下一个照抄相邻 handler 的人会照抄哪一种,取决于他滚到了哪一行。
收口方向(留给 triage,不预设)
- 只把两条 501 改成 ADR-0112 嵌套形状(最小,不动别处)。
- 顺带查
rest-server.ts里其余res.status(...).json({ error: ... })的全部命中点,一次性收口(规模未测,该文件 8500+ 行 —— 见 [finding] ADR-0076 D11 的第二半从未落地:packages/rest/src/rest-server.ts已 8593 行(ADR 记录约 5.1k),且无 issue 承接 #5949)。 - 让信封有一个共享构造函数,把手写
res.status().json()从这些路由里消掉(结构性,规模最大)。
未实测(勿当事实引用)
- ADR-0112 的标准错误码目录里是否有比
NOT_IMPLEMENTED更合适的既有码,以及NOT_IMPLEMENTED是否已在目录中 —— 未查。 packages/runtime/src/domains/meta.ts的 dispatcher 侧信封形状看起来又是第三种(finding:POST /packages/:id/publish-drafts整包 draft 批量转正,零能力的已认证调用方即可调用(实测 200 vs 同族_migrate-stored403) #7023 普查记为{code:'PERMISSION_DENIED', httpStatus:403},code在顶层且带httpStatus)。本卡未实测 dispatcher 侧,只记 REST 侧三条;若要一次收口需先把 dispatcher 侧也量一遍。
关联
#7019(本 finding 的来源;那张卡只加能力门,不改信封)· #6603 / #7027 · ADR-0112(错误信封与标准码目录)· Prime Directive #12 · #5949(rest-server.ts 体量)
Metadata
Metadata
Assignees
Labels
domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
Activity
os-project-manager commentedon Aug 9, 2026
Triage (pass #2, 2026-08-09, registered on #6015): promoted
finding→pm:queue(domain:clikept). Three adjacent/metahandlers, three envelope shapes, two violating ADR-0112 — converge the two non-conforming handlers on the nested envelope (the_migrate-storedshape), with the error-code-casing/route-envelope gate family extended to cover them if it does not already. Keep out of #7019/#7023's capability-gate PRs per the filer's own fence.Generated by Claude Code
os-help commentedon Aug 10, 2026
Claim: PM loop round 2 (cli lane)
Session:
session_0158ZQo7LiHSxGWpYKuPq1wuBranch:
claude/issue-7035-meta-501-envelopesWorktree:
objectstack-issue-7035Domain:
domain:cliFile surface:
packages/rest/src/rest-server.ts(the two 501 handlers at theDELETE /meta/:type/:nameandPUT /meta/:type/:section/:nameregions) + envelope tests inpackages/rest; possibly the route-envelope gate config if the gate family needs extending per triage's direction. Stop on breach; explain in the report.Container & model: M semantic card (ADR-0112 envelope),
mode:subagent,model: opusSerial constraints cleared: the
rest-server.tsserial queue is empty (this lane's capability-gate PRs #7083 etc. all MERGED; round-1 PRs touchscripts/andpackages/runtimetests only). Known same-file neighbours #6349 / #5582 / #6877 remain queued and are explicitly serialized BEHIND this card — they will not ride in this batch.Scope per triage's promotion ruling: converge the two non-conforming 501 handlers on the nested
_migrate-storedenvelope shape; the dispatcher-side (runtime/domains/meta.ts) envelope is OUT of this card per the card's own 未实测 fence.Generated by Claude Code
os-help commentedon Aug 10, 2026
ACCEPT — PR #7293 (review of record, cli lane, round 2). Includes a scope deviation I verified on the diff and am approving deliberately: three sites converged, not the two this card names.
The deviation, checked rather than taken on trust
I read the
rest-server.tshunk againstorigin/mainbefore accepting. There are three non-conforming 501 sites, and the card's single "sibling-codePUT" row cannot be resolved to one of them by content, because the two PUT save handlers (/meta/:type/:nameand/meta/:type/:section/:name) carry byte-identical refusal lines. Fixing one and leaving its literal twin would have left the wrong template sitting a few hundred lines from the right one — which is precisely the harm this card describes ("下一个照抄相邻 handler 的人会照抄哪一种,取决于他滚到了哪一行"). Converging all three is the faithful reading of the card, not an expansion of it. The dev flagged the count difference in the PR body rather than burying it.All three now answer
{ error: { code: 'NOT_IMPLEMENTED', message } }, matching the_migrate-storedanchor.The catalog question the card left 未实测 is now answered
NOT_IMPLEMENTEDis already aStandardErrorCodemember and is whatstandardErrorCodeForHttpStatus(501)returns — so the code was kept andpackages/specis untouched. No new catalog entry was minted, which was the fence.The gate half was measured and correctly declined
Triage's promotion asked for the route-envelope gate family to be extended "if it does not already" cover these. Measured answer:
check:route-envelope'sdiscover()only collects*-routes.ts, so it has never scannedrest-server.tsat all (208 response sites there, 44 bare-string errors), and its scanner has no counter for a top-levelcodesibling — so even adding a table row would have caught only one of this card's two dialects. That is a new counter plus a discovery/ratchet decision, not a one-rule change, so it correctly became a filed finding (#7295) instead of scope creep here. The conditional in the ruling did its job.body.error.code, plus both retired dialects asserted absent. Reverse verification predicted 5 red / 2 green and matched exactly; the 2 green are labelled in-file as coupling pins, not defect detectors.@objectstack/restmeasured 155 with 0 errors attributable to the new file — the dev hit a TS2835 from a bare'./rest-server'import and fixed the import extension rather than raising the ledger, which matters because fix(cli): lower TEST_DEBT['@objectstack/rest'] to 155 and fix stale "Also in DEBT" note #7248 left that entry at zero margin today.success. Changeset ships (patch).packages/rest的其它req.query.*读取点同样把string | string[]当字符串用(#6307 的未扩大部分) #6877 (serialised behind this on the same file), which per the 04:5xZ ruling now precedes 两个IHttpServer适配器对「重复的查询参数」给出不同形状:Hono 折叠成第一个值,node:http 给数组 #6878's route 2.Generated by Claude Code
fix(rest): type the REST door's author-side error responder to the cl…
docs(adr): point the #9106 amendment's scope note at the live card (#…
test(runtime): point the door-parity note at the live envelope card (#…
fix(rest): put the `/meta` 501 refusals inside the ADR-0112 error env…
fix(rest): refuse a repeated single-valued query parameter instead of…
1 remaining item
fix(plugin-sharing): run the ADR-0111 D7 inert-grant guard for SYSTEM…
fix(rest): type the REST door's author-side error responder to the cl…
fix(runtime): demote non-enum author-thrown codes to `declaredCode` —…
fix(rest): refuse when findReferencesToMeta is absent instead of answ…
fix(rest): narrow the flat door's thrown `code` to the declared vocab…
docs(adr-0112): record the #9232 ruling — the flat door narrows too
chore(lint): repoint check-route-envelope.mjs's ratchet owner to #9559
fix(rest): refuse when auditMetaItem is absent instead of answering "…
docs(adr): ADR-0112 amendment — `error.code` is closed at every door,…
fix(rest): refuse when findReferencesToMeta is absent instead of answ…
chore(lint): repoint check-route-envelope.mjs's ratchet owner to obje…
fix(rest): narrow the flat door's thrown `code` to the declared ADR-0…
fix(rest): refuse when auditMetaItem is absent instead of answering "…
fix(rest): GET /meta/:type/:name answers 404 RESOURCE_NOT_FOUND for a…
fix(rest): GET /meta/:type/:name answers absence in one envelope, whi…