Symptom
Nothing on a host-config deploy refuses an ADR-0090 D11 OWD violation. Studio turns the external-OWD description amber and says "publishing will be rejected (ADR-0090 D11)", then leaves Save draft and Publish enabled, and both succeed.
PUT /api/v1/meta/object/qa_probe {…, sharingModel:'private', externalSharingModel:'public_read'}
- Expected 403
owd_external_wider. - Actual 200;
GET returns the violating pair persisted — on the draft path, the active path, and with ?package=. Reproduced 3× on one boot, 3× on a second boot with a fresh DB, plus once through the browser.
Root cause
Located by the run at packages/metadata-protocol/src/protocol.ts. The #3050 authoring-gate call is wrapped in if (this.environmentId !== undefined). The showcase config is a host config (isHostConfig → shouldBootWithLibrary(config) === false), so serve.ts takes the lightweight assembler, which constructs new ObjectQLPlugin() with no options → environmentId stays undefined → the guard is false and runAuthoringGate is never called. So R2 (owd_external_wider) and R1 (owd_widening_forbidden) execute on no self-hosted/host-config deployment.
This is the same proxy-signal hazard #6710 already diagnosed and retired for the sibling #4463 gate. The authoringChannel infrastructure from #6710 exists on origin/main (protocol.ts ~L2929; runAuthoringGate returns early for authoringChannel === 'package-author' ~L3094), but the #3050 gate call site (protocol.ts ~L10003) is still gated on if (this.environmentId !== undefined) — its own comment reaffirms "Environment writes only … environmentId undefined". Confirmed not fixed on origin/main.
The gate logic itself is not the bug: object-posture-gate.test.ts is 18/18 green. A grep for owd_external_wider finds only the gate source and its unit test — there is no integration test exercising R2 through the real save path.
Filed publicly as an authoring-validation gap: external-principal enforcement is #2696-planned, so a wider external baseline does not itself disclose anything today — it is a validation gap, not a live disclosure.
Reproduction
- Boot the showcase app via the CLI host-config path (
serve.ts lightweight assembler). PUT /api/v1/meta/object/qa_probe with {sharingModel:'private', externalSharingModel:'public_read'}.- Observe 200;
GET the object → the violating pair persisted. Repeat with ?package= and against the active path — all 200.
Suggested fix
Key the #3050 gate on the declared authoringChannel, as #6710 did for #4463, instead of on environmentId !== undefined. Add an integration test that exercises R1/R2 through the real save path.
Source
Extracted from the QA run #7637 (framework 92f26f7, console 09987b680).
Symptom
Nothing on a host-config deploy refuses an ADR-0090 D11 OWD violation. Studio turns the external-OWD description amber and says "publishing will be rejected (ADR-0090 D11)", then leaves Save draft and Publish enabled, and both succeed.
PUT /api/v1/meta/object/qa_probe {…, sharingModel:'private', externalSharingModel:'public_read'}owd_external_wider.GETreturns the violating pair persisted — on the draft path, the active path, and with?package=. Reproduced 3× on one boot, 3× on a second boot with a fresh DB, plus once through the browser.Root cause
Located by the run at
packages/metadata-protocol/src/protocol.ts. The #3050 authoring-gate call is wrapped inif (this.environmentId !== undefined). The showcase config is a host config (isHostConfig→shouldBootWithLibrary(config) === false), soserve.tstakes the lightweight assembler, which constructsnew ObjectQLPlugin()with no options →environmentIdstays undefined → the guard is false andrunAuthoringGateis never called. So R2 (owd_external_wider) and R1 (owd_widening_forbidden) execute on no self-hosted/host-config deployment.This is the same proxy-signal hazard #6710 already diagnosed and retired for the sibling #4463 gate. The
authoringChannelinfrastructure from #6710 exists onorigin/main(protocol.ts ~L2929;runAuthoringGatereturns early forauthoringChannel === 'package-author'~L3094), but the #3050 gate call site (protocol.ts ~L10003) is still gated onif (this.environmentId !== undefined)— its own comment reaffirms "Environment writes only … environmentId undefined". Confirmed not fixed onorigin/main.The gate logic itself is not the bug:
object-posture-gate.test.tsis 18/18 green. A grep forowd_external_widerfinds only the gate source and its unit test — there is no integration test exercising R2 through the real save path.Filed publicly as an authoring-validation gap: external-principal enforcement is #2696-planned, so a wider external baseline does not itself disclose anything today — it is a validation gap, not a live disclosure.
Reproduction
serve.tslightweight assembler).PUT /api/v1/meta/object/qa_probewith{sharingModel:'private', externalSharingModel:'public_read'}.GETthe object → the violating pair persisted. Repeat with?package=and against the active path — all 200.Suggested fix
Key the #3050 gate on the declared
authoringChannel, as #6710 did for #4463, instead of onenvironmentId !== undefined. Add an integration test that exercises R1/R2 through the real save path.Source
Extracted from the QA run #7637 (framework 92f26f7, console 09987b680).