Repository navigation
fix(service-automation)!: a connector pull whose input breaks the action's declared inputSchema is refused before dispatch - #28140
Conversation
…ion's declared inputSchema is refused before dispatch The pull door judged nothing before calling the connector action, so a pull missing a parameter the action declares required still reached the remote API. The connector_action node's inputSchema check moves to one module, connector-input-schema.ts, which both doors import: the node's behaviour and messages are unchanged, and the pull door now refuses the input it is about to send (the watermark parameter included) with VALIDATION_ERROR 400 and reason input_schema_mismatch, naming each parameter, before the action is called. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cxUdTtczoG6TtcncPa
📓 Docs Drift CheckThis PR changes 2 package(s): 20 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 6 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 344d67b3b14d1a875b73dfe3fdfe330b6da77927 && git checkout 344d67b3b14d1a875b73dfe3fdfe330b6da77927
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 93242324040563e9db96c98ef186948797d20cbd 9cfb92dd5c26c64c570a8d025b926b36e3d79f61 && git checkout -B drift-repro 93242324040563e9db96c98ef186948797d20cbd && git merge --no-ff 9cfb92dd5c26c64c570a8d025b926b36e3d79f61
node scripts/docs-audit/affected-docs.mjs --json 93242324040563e9db96c98ef186948797d20cbd
|
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Contract-review-claim: The lane seat runs the |
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Contract reviewServed-tier: Reviewed at 2026-10-30T13:55Z, adversarially, on the narrowing face ( ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: FAIL Must-fix:
|
… write, not a CEL cast The pull door evaluates no CEL: connectorSource.input is JSON spread as written and the watermark is the stored value. Its input_schema_mismatch refusal now tells the author to write the value as a JSON number or boolean, and that a watermark parameter is declared with the stored field's type; the connector_action node keeps its int()/double()/bool() hint unchanged. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cxUdTtczoG6TtcncPa
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Contract-review-claim: The lane seat re-runs the |
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Contract reviewServed-tier: Delta review at 2026-10-30T14:02Z, adversarially, of head ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS |
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Seat ACCEPT · PR #28140 · head
|
Requested by Elon · project thread
Fixes #28040
Clause-②: yes (narrowing)
Metadata-protocol: none
Skills-docs: updated here —
content/docs/automation/jobs.mdx("How a run is recorded") andpackages/spec/docs/SYNC_ARCHITECTURE.md("How a pull runs") name the new refusal;skills/**: none —git grep -n -i "connectorSource\|pullConnectorSource\|inputSchema" -- skillshas 1 hit,skills/objectui/guides/plugin-development.md:113(ComponentInputSchema, unrelated), so no skill teaches the pull door.维护者速读
pull)在调用连接器动作前,先用动作声明的inputSchema校验将要发送的输入(含水位参数);不合格即以VALIDATION_ERROR400 拒绝并点名参数,上游零调用。connector_actioncall is dispatched without checking its input against the action's declaredinputSchema, so a missing required parameter reaches the remote API #27995 只给connector_action流程节点加了这道校验,拉取入口仍把缺必填参数的请求发到远端(OpenAPI 路径占位符被原样发送)。failed;回滚即 revert 本 PR。节点的行为与报错文字逐字节不变。packages/services/service-automation/src/connector-pull.ts(新增校验段)、src/connector-input-schema.ts(从节点原样搬出的校验器)、src/builtin/connector-nodes.ts(改为调用共享校验器)。pnpm --filter @objectstack/service-automation exec vitest run --maxWorkers=2 src/connector-pull.test.ts,预期 23/23 通过,其中[#28040]组 5 条。What changes
inputSchemajudgment theconnector_actionnode gained in fix(service-automation)!: a connector_action call whose input breaks the action's declared inputSchema fails before dispatch, naming each parameter #28035 (automation: aconnector_actioncall is dispatched without checking its input against the action's declaredinputSchema, so a missing required parameter reaches the remote API #27995) moves out ofbuiltin/connector-nodes.tsintosrc/connector-input-schema.ts, unchanged byte for byte (the moved block was diffed againstorigin/main's,IDENTICAL). The module exportsfindConnectorActionInputSchema(the descriptor read the node made),judgeConnectorInput(the violations joined as the node joined them, capped at five plus; and N more) andTEXT_FOR_SCALAR_HINT. It is not re-exported from the package entry.code,errorand the cast hint are byte-identical; its existing pins (connector-input-schema.test.ts, untouched) stay green.pullConnectorSource, the door a job'spullruns) judges the input it is about to send, after the watermark parameter is added and before the handler is called. A failing input throwsConnectorPullErrorwithcode: 'VALIDATION_ERROR',status: 400(the pair the door already uses for its other input faults) andreason: 'input_schema_mismatch', and the message names each parameter by dotted path, says nothing was pulled, and points atGET /api/v1/automation/connectors. Nothing is called upstream and nothing is written.Clause-②: yes (narrowing), re-derived from the diff rather than the order'sno (narrowing)):ConnectorPullRefusalReasongains'input_schema_mismatch', andConnectorPullRegistrynow extendsConnectorInputSchemaSource, which requiresgetConnectorDescriptors(). The automation engine (whatAutomationServicePluginpasses) already has it; a hand-built registry adds it..changeset/28040-connector-pull-input-schema.md:patch, BREAKING banner, both declaration lines, ADR-0087not-required (no-migration-prescription)marker, FROM / TO / fix.Why
Prime Directive #10: a rule holds at every call site. Triage 6521041814 graded the pull door as the sibling call site of #27995, to be judged by the same check through one helper and refused before dispatch, naming the parameter.
Tests
main(premise holds). The three refusal pins added here, run againstorigin/main'sconnector-pull.ts(8cb8c7f4), fail withthe pull must refuse, not resolve: expected undefined to be an instance of ConnectorPullError: the pull resolved, so it called the action.Tests 3 failed | 20 passed (23).src/connector-pull.test.ts,[#28040]group, through the shippedpullConnectorSourcewith a counting handler):query.since) →VALIDATION_ERROR/ 400 /input_schema_mismatch, the message names'query.since', the handler is called 0 times, nothing is written.missing required 'query' (with 'query.since')), 0 calls.query.limit: '50'againstinteger) → refused naming it, 0 calls; text is not converted.query.sincesupplied only by the watermark pulls (1 call, with the watermark value).Every existing pull pin passes with no
inputSchemadeclared, which is the "no schema ⇒ pull what you are given" leg.node scripts/ablation-replace.mjs, on the committed fix):if (verdict)→if (verdict && false /* ABLATION */)inconnector-pull.ts, landed on disk (anchor 1 → 0, markergrep -c= 1, blob6b358231→349fc8e6). Exactly the three refusal pins turned red (Tests 3 failed | 20 passed (23)); restored,blob == HEAD (6b358231da3f) and git diff HEAD is empty. The tests import./connector-pull.jsfrom source, so nodist/leg applies.Acceptance notes
connectorSource.input).restprovider'srequestaction declares norequiredand its declared types match what a pull writes, so the shippedrestpull (the integration pin) is unaffected;openapiactions are where the check bites.packages/qa/dogfood/test/api-action-door-forward.dogfood.test.ts:178expects theACTION_DISABLEDmessage to containsys_metadata_activation, but feat(spec,metadata-protocol,rest,objectql,runtime): GET /meta/object serves switched-off packaged actions beside the item, and the disabled-action refusal reads as a plain sentence #27964 (3e0fd7a8f7, an ancestor oforigin/main:merge-base --is-ancestorexit 0) rewrote that refusal as a plain sentence. The pin is red onmain; this diff touches no file on that path. Reported to the seat for filing.Verification
All local readings are at head
02de39cc91.Package test + typecheck (service-automation), connector-openapi dispatch pin
pnpm --filter @objectstack/service-automation build→VERDICT command-exit 0pnpm --filter @objectstack/service-automation typecheck→ exit 0 (includescheck:test-typecheck:0 file(s) / 0 error(s))pnpm --filter @objectstack/service-automation test→Test Files 227 passed (227),Tests 2881 passed (2881),VERDICT command-exit 0pnpm --filter @objectstack/connector-openapi exec vitest run --maxWorkers=2 src/input-schema-dispatch.test.ts(fix(service-automation)!: a connector_action call whose input breaks the action's declared inputSchema fails before dispatch, naming each parameter #28035's end-to-end node pin) →Tests 4 passed (4)connector-pull.test.ts,builtin/connector-input-schema.test.ts,builtin/connector-nodes.test.ts,connector-pull.integration.test.ts,connector-pull-service-door.test.ts→Test Files 5 passed (5),Tests 64 passed (64)Derived gate families (dispatch-gates) + pnpm lint
node scripts/pm/dispatch-gates.mjs --commandsderived 92 families from 7 paths vs merge base8cb8c7f46.check-plugin-teardown-shape --self-test(aftergit fetch --unshallow),check:skill-examplesandcheck:dual-build-cjs-loads(after the full build thatcheck:type-check-debtruns).check:type-check-debtfirst queued behind the dogfood run (exit 99, not measured) and passed on re-run:124/127 workspace packages type-checked, 0 in the DEBT ledger.node scripts/pm/dispatch-gates.mjs --ran→92 derived famil(ies) accounted for — 92 run, 0 NOT-MEASURED;pnpm lintrecorded outside the derivation.pnpm lint→ exit 0.check-platform-checklist --changed-fromis not owed.Dogfood battery (the narrowing arm owes it)
pnpm --filter '@objectstack/dogfood^...' build→ exit 0;pnpm --filter @objectstack/dogfood testunder the lock →VERDICT command-exit 1,Test Files 1 failed | 357 passed | 3 skipped (361),Tests 1 failed | 2882 passed | 20 skipped (2903).api-action-door-forward.dogfood.test.ts > the switch holds: ban_user OFF answers 409 ACTION_DISABLED…:expected 'This action is turned off for this de…' to contain 'sys_metadata_activation'. That is the stale pin onmainnamed under Acceptance notes, not a consequence of this diff (no automation or connector path).Human Minimum
packages/specholds no runtime logic. (No schema touched.)pnpm lintpasses.main, one pull request.packages/spectouched: onlydocs/SYNC_ARCHITECTURE.md(not infiles[], no generator reads it), so nothing to regenerate.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code