fix(spec): connector preserves the ADR-0010 protection envelope instead of silently stripping it (#6362) - #6900
Merged
Conversation
`ConnectorSchema` tolerated the ADR-0010 protection envelope but never declared it, so every package-load round-trip through the schema dropped all seven `_`-prefixed keys with no error anywhere. Tolerate is not preserve. Both metadata load paths call `applyProtection` on every type, and since #6245 bound `DeclarativeConnectorEntrySchema` to `PUT /meta/connector/:name`, something re-parses that stamped body on every write. This is the quiet half of the pair #6245 fixed. `sharing_rule` is `.strict()`, so its undeclared envelope was REJECTED — a hard 422, loud, fixed there. `ConnectorSchema` is a plain `z.object`, so it ACCEPTED the envelope, answered success, and stripped it — leaving every reader of `extractProtection` / `resolveLockState` looking at an unlocked, unattributed, org-provenance item. Fix is the single `...MetadataProtectionFields` spread #6245's dev verified on `sharing_rule`. Pure-additive and internal; the schema stays non-strict, so an undeclared `_` key is still stripped. `webhook` was measured in the same pass and needs no change — it has carried the spread since #4001 batch 11 and all seven keys already survive. That reading is now pinned rather than left as a note. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011sGk4SKHqGRgmmqUok1P8M
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 113 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…ope keys (#6362) `content/docs/references/integration/connector.mdx` is GENERATED from the spec schemas. The `...MetadataProtectionFields` spread adds seven optional keys to `ConnectorSchema`, so the reference page's property tables go with it. Regenerated with `pnpm --filter @objectstack/spec gen:schema && ... gen:docs`, never hand-edited. Caught by the `check:docs` gate in the TypeScript Type Check job. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011sGk4SKHqGRgmmqUok1P8M
os-zhuang
marked this pull request as ready for review
August 9, 2026 04:29
This was referenced Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6362
Premise — re-verified at
origin/main, and it heldConnectorSchemais still a non-strictz.objectwith no ADR-0010 protectionenvelope. Measured before any edit, by round-tripping a loader-stamped catalog
descriptor through the schema the metadata registry actually resolves for
connector:All seven keys gone,
success: true, no error anywhere. Tolerate is notpreserve.
Why this one outlived its two siblings
Both metadata load paths call
applyProtectionon every type, so apackage-loaded connector carries the envelope by the time anything re-parses
it — and since #6245 bound
DeclarativeConnectorEntrySchematoPUT /api/v1/meta/connector/:name, something re-parses it on every write.The pair splits by posture, and the quiet half is the one that survived:
sharing_rule.strict()connectorz.objectEvery downstream reader of
extractProtection/resolveLockStatethereforesaw an unlocked, unattributed,
org-provenance connector where the loader hadstamped a locked, package-owned one.
The fix
One
...MetadataProtectionFieldsspread onConnectorSchema— the shape#6245's dev verified on
sharing_rule. Pure-additive and internal: every keyis
_-prefixed and optional, no author-facing field changes, and nothing thatparsed before stops parsing.
ConnectorSchemastays non-strict (subtypes.extend()it), so the spread adds seven named keys, not a passthrough —an undeclared underscore key is still stripped, and that is pinned.
MANDATORY: the
webhookmeasurement — PRESERVED, no drop, no spread appliedThe card asked whether
webhookhad the same defect and to apply the samespread only if it did. It does not, so nothing was applied there.
Probe — the same round-trip used for
connectorabove, driven throughgetMetadataTypeSchema('webhook')(the/metawrite door #6245 bound) with afully populated seven-key envelope, asserting the parse output key by key:
all seven survive. Reading confirms it:
WebhookSchemahas carried...MetadataProtectionFieldssince #4001 batch 11, and the generatedintegration/WebhookConfig:_packageIdbaseline entry already recorded it.That reading is now a pin, not a note in a closed report
(
webhook.test.ts,[#6362] PRESERVES all seven envelope keys — measured, not assumed), so it cannot regress unobserved. The pre-existing #4001 test assertedonly two keys and only that the envelope was accepted — enough for "accepts",
not for "preserves", and an accepts-shaped assertion is exactly what was green
on
connectorthroughout.Reverse verification — direction predicted first, then measured
Prediction: removing the spread turns the new preservation pins red while
every pre-existing
connectorassertion stays green. That asymmetry isthe defect's signature — the unfixed schema parses the stamped body perfectly
well, so only an assertion over the parse output can see it.
Measured (spread removed via
git checkout origin/main -- connector.zod.ts,restored from the commit afterwards):
5 red, 186 green — including all pre-existing
connectortests and bothwebhookenvelope tests. Exactly the predicted direction.Tests
New
describe('ADR-0010 protection envelope (#6362)')inconnector.test.ts, driving the round-trip at all three levels, because thebase schema carrying the spread is only half an answer if the bound door drops
it:
ConnectorSchema— all seven keys asserted by value;DeclarativeConnectorEntrySchema— the/metawrite door meta: bind Zod schemas for webhook / connector / sharing_rule WITHOUT registering the kinds — close the unvalidatedPUT /metawrite hole (#2657 audit, option A) #6245 bound;getMetadataTypeSchema('connector')— the registry lookup, so a futurerebinding to a third shape cannot pass the first two and still strip in
production;
§3/§5 cross-field rules;
WebhookConfigSchema, so the inherited behaviour cannot regress through afuture
.extend()/.omit()on the connector side.No new test files, so the type-check coverage ledger is untouched.
Generated baselines
packages/spec/authorable-surface/integration.jsongains the sevenintegration/Connector:_*keys, regenerated by the spec build — matching what#6245 recorded for
security/SharingRuleandsecurity/CriteriaSharingRule.authorable-surface.base.jsonwas not rewritten.Generated by Claude Code