Found while implementing the #13279 ruling (PR #13475). No severity is asserted here; this records what was driven and what came back, for triage.
The shape
#13279 ruled that a permission-store READ FAILURE must fail loud, and tryFind now raises AuthzStoreUnavailableError (503 SERVICE_UNAVAILABLE) when a read is issued and throws. That repair does NOT reach a second path to the same disguise, because that path never issues a read at all.
rest-server.ts resolves the data engine as an absorbed rejection:
const ql = kernel
? await kernel.getServiceAsync('objectql').catch(NO_OP_RETURNING_UNDEFINED)
: ...;
So an engine that cannot be RESOLVED becomes ql === undefined. resolveAuthzContext then takes tryFind's guard for an unwired engine and returns an empty grant set — correctly, for its own contract: "no engine is wired" is a legitimate embedder shape and must stay quiet.
The two conditions are not the same fact, and they arrive at the resolver as the same value:
- an embedder that never configured a data plane — zero capabilities is TRUE;
- a deployment whose engine resolution FAILED — zero capabilities is UNKNOWN.
What was measured
Real RestServer, real registerPackageRoutes, wired as rest-api-plugin.ts wires it. Fault class DATA_ENGINE_UNRESOLVABLE in packages/rest/src/package-door-execctx-fault-reachability.test.ts.
| wiring |
GET /api/v1/packages |
| healthy store granting the capabilities |
200 |
| permission store reachable, every read throws |
503 SERVICE_UNAVAILABLE (after #13279) |
| the data engine cannot be resolved at all |
403 FORBIDDEN, unchanged |
The third row still answers "Reading packages requires the studio.access or setup.access capability." to an authenticated administrator whose engine is simply gone. After #13279 it is the LAST surviving member of the GRANTS-LOST disguise on this door, and the inverted test in PR #13475 asserts that residue explicitly rather than leaving it to be rediscovered.
Why this was not folded into #13279
The #13279 ruling names tryFind / resolveUserAuthzGrants as its landing point and speaks of the permission store being unreachable. This seam is neither: it is the TRANSPORT's engine-resolution .catch, one layer out, and the correct behaviour there is a judgement rather than a mechanical consequence of that ruling — quieting it wrongly would refuse service to every embedder with no data plane, which is a supported configuration.
Related, and distinct
None of those is addressed by this card, and this card is not addressed by any of them.
Generated by Claude Code
Found while implementing the #13279 ruling (PR #13475). No severity is asserted here; this records what was driven and what came back, for triage.
The shape
#13279 ruled that a permission-store READ FAILURE must fail loud, and
tryFindnow raisesAuthzStoreUnavailableError(503SERVICE_UNAVAILABLE) when a read is issued and throws. That repair does NOT reach a second path to the same disguise, because that path never issues a read at all.rest-server.tsresolves the data engine as an absorbed rejection:So an engine that cannot be RESOLVED becomes
ql === undefined.resolveAuthzContextthen takestryFind's guard for an unwired engine and returns an empty grant set — correctly, for its own contract: "no engine is wired" is a legitimate embedder shape and must stay quiet.The two conditions are not the same fact, and they arrive at the resolver as the same value:
What was measured
Real
RestServer, realregisterPackageRoutes, wired asrest-api-plugin.tswires it. Fault classDATA_ENGINE_UNRESOLVABLEinpackages/rest/src/package-door-execctx-fault-reachability.test.ts.The third row still answers "Reading packages requires the
studio.accessorsetup.accesscapability." to an authenticated administrator whose engine is simply gone. After #13279 it is the LAST surviving member of the GRANTS-LOST disguise on this door, and the inverted test in PR #13475 asserts that residue explicitly rather than leaving it to be rediscovered.Why this was not folded into #13279
The #13279 ruling names
tryFind/resolveUserAuthzGrantsas its landing point and speaks of the permission store being unreachable. This seam is neither: it is the TRANSPORT's engine-resolution.catch, one layer out, and the correct behaviour there is a judgement rather than a mechanical consequence of that ruling — quieting it wrongly would refuse service to every embedder with no data plane, which is a supported configuration.Related, and distinct
.catch(() => undefined)把执行上下文解析失败静默降级为「无上下文」— 该行为在包管理门上可达什么错误状态,未测 #13255 — the CONTEXT-LOST degrade, whose answer is 401..catch; this one is about what an ABSORBED engine rejection then produces downstream.None of those is addressed by this card, and this card is not addressed by any of them.
Generated by Claude Code