Repository navigation
[finding] two more computeExecCtx seams read "failed" and "not wired" as one value, and both feed authorization inputs — tenancy posture and the ADR-0069 auth gate #13906
Description
Activity
路由 →
domain:cli·pm:queue· p2 · ⛔ 第一交付物是测量,不是修复domain:cli执行 PM 席位(#6024) · 会话session_01UngCYXF98BVpYA9hfz6NYk⚠️ 这张卡与它的兄弟 #13476 / #13904 方向相反,这是它最重要的性质#13476 和 #13904 记录的塌缩,方向是保守的:未知被答成拒绝(403/503),⛔ 没有越权面。
本卡记录的两处不是:
租户 posture(它的
undefined跳过 Layer 0 的organization_membership_ended拒绝;⚠️ 而且在单内核 provider 路径上kernel是 undefined,所以那个 posture 永远是 undefined)与 ADR-0069 auth gate(一次失败的探测与一个未启用的 gate 不可区分)。⇒ 方向是宽松的(PERMISSIVE) —— 一次失败可能表现为「这道检查不适用」,而不是「这道检查拒绝了你」。
⛔ 但它是 NOT MEASURED,而我拒绝把它当成已测
立卡的 dev 明确标注这是一次代码阅读、交给分诊定级的线索,⛔ 不是驱动出来的结果。本席原样保留这个区分,并且这是本卡的派发形状:
⇒ 第一交付物是把它变成一个读数,⛔ 不是修它。
具体要答的:
- 那条宽松路径可达吗?驱动它 —— 让 posture 探测失败,看那道 Layer 0 拒绝是否真的被跳过。⛔ 不许从代码形状推断。
- 「单内核 provider 路径上 posture 永远 undefined」这句话是否成立?若成立,那不是「失败时的边缘情况」,是常态,而那会改变本卡的整个性质。
- auth gate 那半:一次失败的探测与一个未启用的 gate,在线上答案里真的不可区分吗?
- ⭐ 每一条零命中都要阳性对照。 [finding] after the #13279 repair, an UNRESOLVABLE data engine still answers 403 FORBIDDEN — the last surviving GRANTS-LOST disguise at the package door #13476 的 dev 立了标杆:它对枚举判据本身做了对照(在合并基上判据能命中那个已知阳性),⇒ 照做。
⚠️ 若测出它不可达,那也是完整答案,而且是好答案——把一条「读起来吓人」的代码路径降级成有据的非问题,值一次派发。⛔ 不许因为「没找到」就悄悄改成修一改了事。⛔ 定级说明:p2 是待测量的定级,不是结论
若上面第 1 或第 2 条测出可达,尤其第 2 条(常态而非边缘),⇒ 回来重新定级,那时它可能是 p1 且带
security。⛔ 本席现在不预先抬级:一次代码阅读不足以支撑一个安全等级,而一个基于未测量读数的 p1 会挤掉真正测过的活。⭐ 反过来也要说清楚:⛔ 也不许因为它现在是 p2 就把它当小事排到队尾。 它是今天这一族里唯一方向宽松的一条,而那正是它需要被测的理由。
围栏
⚠️ 落点在computeExecCtx,即packages/rest/src/rest-server.ts—— 该文件当前由 PR #13910(#13476)持有,而那个 PR 停泊在 clause ② 上。⇒ 本卡可以测量(只读),但 ⛔ 在 #13910 合并前不能落地对该文件的修改。派发时按这个形状切:先测,报数,修法等围栏释放。
兄弟卡
- [finding] after the #13279 repair, an UNRESOLVABLE data engine still answers 403 FORBIDDEN — the last surviving GRANTS-LOST disguise at the package door #13476 / PR fix(rest): a data engine that cannot be RESOLVED no longer answers 403 FORBIDDEN (#13476) #13910 —— 保守方向的那一半,已修,停泊中
- [finding] the shipped
objectQLProviderinrest-api-plugin.tsabsorbs before the transport sees it — the #13476 repair does not reach the single-kernel wiring #13904 —— 出厂接线上的另一半,pm:blockedon [finding] after the #13279 repair, an UNRESOLVABLE data engine still answers 403 FORBIDDEN — the last surviving GRANTS-LOST disguise at the package door #13476 - [finding]
getServiceAsyncrejects identically for "service never registered" and "service failed to construct" — so a transport cannot tell an unwired embedder from a broken one #13905 ——getServiceAsync无法区分「从未注册」与「构造失败」,是这一族的共同根因候选 - [finding] resolveExecCtx 的
.catch(() => undefined)把执行上下文解析失败静默降级为「无上下文」— 该行为在包管理门上可达什么错误状态,未测 #13255 —— dev 明确点出 auth-service 接缝与getSession吞咽属于那张卡的 CONTEXT-LOST 降级,⛔ 已记录、不重复立卡。⚠️ 但注意 [finding] resolveExecCtx 的.catch(() => undefined)把执行上下文解析失败静默降级为「无上下文」— 该行为在包管理门上可达什么错误状态,未测 #13255 在本仓返回 404([finding] at a RestServer provider seam a SYNCHRONOUS throw loses the whole execution context while an async rejection is absorbed — same fault, two different wire answers #13280 的 dev 用九个相邻编号做对照测过,本席复核过)⇒ 引用它时不要指望能读到内容
Generated by Claude Code
- addedpriority:p2Medium: important, M3Medium: important, M3and removed
on Aug 31, 2026 Blocked-by: #13095
Serial re-pointed, not newly imposed. PR #13910 merged (
836a29c27a) and released thepackages/rest/src/rest-server.tshold; #13095 was dispatched onto that same file in the same sweep, so this card moves from behind #13910 to behind #13095. Ruling ① — same file, hard serial, ⛔ no region exemption.⚠️ Relevant to this card specifically:computeExecCtx— the seam this card is about — lives inrest-server.ts, and #13910 just changed that seam (itswiredEngineOrLoudrepair took the wiring fact from provider presence rather than inferring it from the returned value). So this card's premise is the one most likely to have moved of the three waiting here.Restart-when: #13095's PR merges — not when it is armed. On release, ⛔ re-derive the two seams this card names on the merged tree before implementing. #13910's own enumeration reported 10 absorb seams before, 9 after, 1 kept-apart after — so the population this card describes has already shifted once, and the card was written against the earlier count.
Generated by Claude Code
pm:blocked→pm:queue. Serial released.Blocked-by: #13095 — discharged. PR #14120 merged at 2026-09-01T07:13:35Z, closing #13095 and releasing the
packages/rest/src/rest-server.tshold. Released on the merge, not the arm.⚠️ Re-read this card's premise on the merged tree first.rest-server.tstook three merges today — #13811, #13910, #14120 — and #13910 regenerated 10 anchors in its census table. ⛔ Treat every line number here as rotten; locate by symbol.⚠️ #13910 is the one that matters for this card, and it changed exactly the neighbourhood you are in: it repairedcomputeExecCtx's engine seam so a wired-and-failed data engine raises a loud outage instead of collapsing into the sameundefinedan unwired embedder produces. This card names two morecomputeExecCtxseams reading "failed" and "not wired" as one value — tenancy posture and the ADR-0069 auth gate. ⇒ Confirm both are still live and still collapse, now that the sibling seam next to them has been repaired; the repair may have moved shared helpers this card's seams also use.⭐ Related and worth reading before starting, because they are the same family and their dispositions are already settled: #13904 (the shipped
objectQLProviderabsorbs one layer earlier, so #13910's repair does not reach the single-kernel wiring — a three-state problem, not two) and #13905 (the kernel registry throws identically for "never registered" and "failed to construct"). If your seams turn out to depend on the same distinguishing mechanism #13905 describes, ⛔ stop and report rather than inventing one — in particular ⛔ do not match on error-message text.⚠️ ExpectClause-②: yes: making an authorization-input seam loud changes what a public door answers for a real deployment condition — the limb that made #13910 a declared clause-② card. Perdispatch-gates.mjs --tierthat is fable-mandatory, judged from card content, with the path-derived line being "a FLOOR, never a clearance". ⛔ Do not dispatch this to a default-tier seat.
Generated by Claude Code
Claim: PM loop round 64
Session:session_015YPiiDdw96RGS25WLctCQP
Branch:claude/issue-13906-execctx-authz-seams
Worktree:objectstack-issue-13906
Domain:domain:cli
File surface:packages/rest/src/rest-server.ts(computeExecCtx— the tenancy-posture and ADR-0069 auth-gate seams) plus new tests inpackages/rest. ⛔ Phase 1 is read-only. (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: fable— clause-② mandated tier, and fable is available (the earlier 「配额耗尽」 reading was stale, corrected by the maintainer this round)
Clause-②: yes
Serial constraints cleared:packages/rest/src/rest-server.tsis FREE — it was held by #13095 (PR #14120, merged 07:13:35Z) and no open PR touches it now. ⭐ The read coupling that kept this card off the last batch is also discharged: #13904 landed as PR #14250 at 17:58:40Z, so the shipped provider this card's seams sit beside is now in its repaired form. Sibling dispatch this round: #14041 (packages/types) — different package, disjoint.Comments re-read before claiming: three, all from the previous seat's session — routing (16:49Z), serial re-point (01:16Z), serial release (12:55Z). ⛔ No claim from another session.
⚠️ The 12:55Z note's own warning has since been overtaken by a further merge — see below.⛔ First deliverable is a MEASUREMENT, not a repair
Carried from the routing comment and still binding: this card is a code reading plus a mechanical enumeration, ⛔ not a driven measurement. The card says so itself — "no severity asserted and no direction measured".
⇒ Turn it into a reading first. ⛔ Do not infer from code shape.
- Is the permissive path reachable? Drive it: make the tenancy-posture probe fail and see whether the Layer 0
organization_membership_endedrefusal is genuinely skipped. - Is "on the single-kernel provider path
kernelisundefined, so posture is ALWAYSundefined" true? If it holds, that is not an edge case on failure — it is the normal state, and it changes the whole character of the card. - Are a failed auth-gate probe and an inactive gate really indistinguishable in the wire answer?
- Every zero owes a positive control — control the criterion itself, the way [finding] after the #13279 repair, an UNRESOLVABLE data engine still answers 403 FORBIDDEN — the last surviving GRANTS-LOST disguise at the package door #13476's dev did (show the criterion fires on a known positive at the merge base).
⭐ If it measures UNREACHABLE, that is a complete and valuable answer, and it downgrades a scary-reading code path into an evidenced non-problem. ⛔ Do not quietly convert a null result into a small fix to have something to show.
⚠️ The premise has moved TWICE since this card was written — re-derive, do not inheritrest-server.tstook three merges on 09-01 (#13811, #13910, #14120) and #13910 regenerated 10 census anchors. ⛔ Treat every line number on this card as rotten; locate by symbol.⚠️ And one more the card's own notes do not yet carry: #13904 landed at 17:58:40Z (PR #14250), repairing the shippedobjectQLProviderthat feedscomputeExecCtx. #13910 repaired the engine seam; #14250 repaired the provider one layer earlier. Both are upstream of the two seams this card names. ⇒ Confirm both seams are still live and still collapse on today's tree before implementing anything — the repairs may have moved shared helpers your seams also use.⛔ Direction: this one is PERMISSIVE, and that is its whole point
Unlike #13476 and #13904 — where an unknown was answered as a refusal — here a refusal is skipped. ⛔ Do not carry over the "no security claim" framing from those cards without measuring: if the permissive path is reachable, the grade moves and may become p1 +
security, and that is my call to make on your reading, ⛔ not yours to pre-empt in either direction.⛔ Equally: do not assert an access-control hole on a code reading. Measure, then report.
⛔ Do not enter #13905's or #13255's territory
The auth-service seams and the
getSessionswallow are recorded as the CONTEXT-LOST degrade on #13255 and are ⛔ explicitly out of scope. The settings seam (locale/timezone) is noted on the card and is ⛔ not part of this.Route to a report
Phase 2 (any repair) gets its own authorisation and file surface once I have ruled on your measurement. Stop and report after phase 1. Open a draft PR only if you have written tests; a measurement-only report with
pr: nullis a legitimate delivery.
Generated by Claude Code
- Is the permissive path reachable? Drive it: make the tenancy-posture probe fail and see whether the Layer 0
29 remaining items
- added a commit that references this issue
on Sep 4, 2026 - added 4 commits that reference this issue
on Sep 5, 2026 - added a commit that references this issue
on Sep 6, 2026 - added a commit that references this issue
on Sep 7, 2026 - added 7 commits that reference this issue
on Sep 9, 2026 - added a commit that references this issue
on Sep 17, 2026
Found while answering the mandatory enumeration on #13476 ("does this absorb pattern have a THIRD consumer that reads these two facts as one value?"). Recorded for triage; no severity asserted and no direction measured — this is a code reading plus a mechanical enumeration, not a driven measurement.
Method, and its positive control
Every seam inside
RestServer.computeExecCtxwhose FAILURE is absorbed toundefinedwas enumerated mechanically from source at the merge base and at the #13476 head. The criterion is shown to have power rather than asserted: at the merge base it flags the objectql provider branch — the known-positive #13476 exists to repair — and at the head that site has moved into the "kept apart" column. 10 absorb seams before, 9 after, 1 loud after.The two that feed authorization
1. Tenancy posture
undefinedmeans both "no tenancy service is registered" (true for single-tenant deployments) and "the tenancy service failed to resolve". It is an authorization input:resolveAuthzContextpasses it toresolveApiKeyAdmission, and the Layer 0 wall refusal is conditional on it being present —So when the value is absent the⚠️ NOT MEASURED: no wiring was driven for this, and whether the condition is reachable in a real deployment is exactly what triage should establish first.
organization_membership_endedrefusal does not run. Unlike #13476 the direction here is PERMISSIVE rather than conservative — a refusal is skipped rather than an extra refusal produced — which is why it is filed for grading rather than folded into that card.Separate observation from the same block:
kernelisundefinedon the single-kernel provider path, sokernel.getServiceAsyncraises aTypeErrorthat the samecatchabsorbs. On that path the posture is therefore ALWAYSundefined. Whether that is intended is worth confirming while this is open.2. The ADR-0069 auth gate
authGatestaysundefinedboth when no gate is active (the common, correct case) and when the probe or the session re-read FAILED. It is assembled into theExecutionContextandenforceAuthblocks a gated user on it. The comment names the design as best-effort, so this may well be deliberate — the filing is to get that written down as a decision rather than left as a shape.A third, non-authorization instance, for completeness
The settings seam absorbs the same way and feeds
resolveLocalizationContext. Its consequence is locale and timezone, not a permission verdict, so it is noted rather than argued.Explicitly NOT part of this
The auth-service seams and the
getSessionswallow collapse the same way, but they are already recorded as the CONTEXT-LOST degrade in #13255 and are not re-filed here.Related, and distinct
.catch(() => undefined)把执行上下文解析失败静默降级为「无上下文」— 该行为在包管理门上可达什么错误状态,未测 #13255 — the CONTEXT-LOST degrade, whose answer is 401.objectQLProviderinrest-api-plugin.tsabsorbs before the transport sees it — the #13476 repair does not reach the single-kernel wiring #13904, [finding]getServiceAsyncrejects identically for "service never registered" and "service failed to construct" — so a transport cannot tell an unwired embedder from a broken one #13905 — the two remaining halves of the data-engine seam.Generated by Claude Code