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.computeExecCtx whose FAILURE is absorbed to undefined was 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
let tenancyPosture;
try {
tenancyPosture = effectiveTenancyPosture(await kernel.getServiceAsync('tenancy') as any);
} catch {
tenancyPosture = undefined;
}
const authz = await resolveAuthzContext({ ql, headers, getSession, tenancyPosture });
undefined means both "no tenancy service is registered" (true for single-tenant deployments) and "the tenancy service failed to resolve". It is an authorization input: resolveAuthzContext passes it to resolveApiKeyAdmission, and the Layer 0 wall refusal is conditional on it being present —
if (keyPrincipal?.tenantId && input.tenancyPosture) {
const posture = input.tenancyPosture;
if (postureEnforcesWall(posture) && !grants.accessible_org_ids.includes(keyPrincipal.tenantId)) {
return { ..., authRefusal: { reason: 'organization_membership_ended', ... } };
}
}
So when the value is absent the organization_membership_ended refusal 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. ⚠️ 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.
Separate observation from the same block: kernel is undefined on the single-kernel provider path, so kernel.getServiceAsync raises a TypeError that the same catch absorbs. On that path the posture is therefore ALWAYS undefined. Whether that is intended is worth confirming while this is open.
2. The ADR-0069 auth gate
let authGate: AuthGate | undefined;
try {
if (typeof authService.isAuthGateActive === 'function' && authService.isAuthGateActive()) {
const gatedSession: any = await getSession(headers).catch(() => undefined);
authGate = normalizeAuthGate(gatedSession?.user) ?? undefined;
}
} catch { /* gate is best-effort - never break context resolution */ }
authGate stays undefined both when no gate is active (the common, correct case) and when the probe or the session re-read FAILED. It is assembled into the ExecutionContext and enforceAuth blocks 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 getSession swallow 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
Generated by Claude Code
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