Skip to content

feat(automation): schema-aware flow-condition validation at registration (#1928) - #3190

Merged
os-zhuang merged 1 commit into
mainfrom
claude/flow-registration-schema-aware-validation
Jul 18, 2026
Merged

feat(automation): schema-aware flow-condition validation at registration (#1928)#3190
os-zhuang merged 1 commit into
mainfrom
claude/flow-registration-schema-aware-validation

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

Brings the registerFlow runtime path up to parity with objectstack build: a flow condition that references an unknown field, likely-typos a field name, or does arithmetic/ordering on a text/boolean field against a number is now surfaced at registration — so a flow registered dynamically (API / Studio, bypassing the build lint) still gets the #1928 guardrails.

This is the real, tractable version of the "authoring-time feedback" follow-up noted in #3178. (There is no validate_expression agent tool in the codebase to wire into; the flow-registration path is the actual runtime authoring surface.)

Stacked on #3178 (base = claude/cel-js-arithmetic-null-2xtg4s). It consumes the tier-4 fieldTypes/flattened-scope check added there. GitHub will retarget this to main once #3178 merges; the diff stays just this change.

Design — strictly additive, zero regression

  • New opt-in bridgeAutomationEngine.setObjectSchemaResolver(resolver), mirroring the existing setFunctionResolver. AutomationServicePlugin wires it to objectql.registry.getObject in start(), before the flow pull, so registry-sourced flows are covered too.
  • validateFlowExpressions keeps its fatal set unchanged (syntax, brace-in-CEL, unknown-function still throw). When a resolver is wired, a second schema-aware pass runs only on syntactically-valid conditions and its findings (field-existence, tier-3 typo, tier-4 type mismatch) are logged as advisory warnings — never thrown. So a wired resolver can never break a flow that used to register cleanly, and the whole thing is a no-op when unwired.
  • Flow conditions bind the record's fields flat → the check runs in flattened scope: flow variables stay dyn (never flagged), equality stays runtime-safe.
  • parseObjectFieldSchema normalizes the registry's field shape (name-keyed map — the ServiceObject shape — or {name,type}[]) into the validator's hint.

Why advisory (not fatal) at registration

The build gate (objectstack build) is strict and fails the build. Runtime registerFlow is deliberately lenient — a running system should log a suspicious dynamically-registered flow, not refuse to register it (and a resolver fed a partial field list must never hard-break registration). Same guardrail, appropriate severity per surface.

Testing

  • @objectstack/service-automation316 green (+10):
    • 6 engine cases: tier-4 / tier-3 / tier-2 each log an advisory warning and do not throw; sound conditions (number arithmetic, equality, flow variables) stay clean; a malformed condition still hard-fails; no-op without a resolver.
    • 4 parseObjectFieldSchema cases: map shape, array shape, non-string type → dyn, invalid input.
  • Full existing suite unchanged (306 → 316); DTS build type-checks clean.

Refs: #1928, ADR-0032. Builds on #3178 (tier-4), #1930 / #1931 / #1933.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Hnji7EEYR2mGt6pY53a8Bm


Generated by Claude Code

@vercel

vercelBot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 18, 2026 8:15am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 18, 2026
@github-actions

github-actionsBot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): packages/services.

6 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/webhooks.mdx(via packages/services)
  • content/docs/kernel/runtime-services/audit-service.mdx(via packages/services)
  • content/docs/kernel/runtime-services/index.mdx(via packages/services)
  • content/docs/kernel/runtime-services/settings-service.mdx(via packages/services)
  • content/docs/plugins/packages.mdx(via packages/services)
  • content/docs/protocol/kernel/i18n-standard.mdx(via packages/services)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Base automatically changed from claude/cel-js-arithmetic-null-2xtg4s to mainJuly 18, 2026 07:13
…ion (#1928)
registerFlow now runs the same schema-aware condition checks as objectstack
build, so a flow registered dynamically (API/Studio, bypassing the build lint)
still gets the guardrail. When an object-schema resolver is wired, a condition
that references an unknown field, likely-typos a field, or does arithmetic/
ordering on a text/boolean field against a number is surfaced as an advisory
warning (logged), against the object's real schema.
- New AutomationEngine.setObjectSchemaResolver bridge (mirrors
setFunctionResolver); AutomationServicePlugin wires it to
objectql.registry.getObject in start(), before the flow pull.
- Strictly additive: the fatal set is unchanged (syntax, brace-in-CEL,
unknown-function still throw); schema findings are logged, never thrown;
no-op when unwired. Flattened scope — flow variables stay dyn, equality safe.
- parseObjectFieldSchema helper normalizes the registry's field map/array.
Tests: service-automation 316 (+10: 6 engine resolver, 4 parser); no regression.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hnji7EEYR2mGt6pY53a8Bm
@os-zhuang
os-zhuangforce-pushed the claude/flow-registration-schema-aware-validation branch from 79f41ea to adf2015CompareJuly 18, 2026 07:14
@os-zhuang
os-zhuang marked this pull request as ready for review July 18, 2026 07:28
@os-zhuang
os-zhuang merged commit 780b4b5 into mainJul 18, 2026
15 of 16 checks passed
@os-zhuang
os-zhuang deleted the claude/flow-registration-schema-aware-validation branch July 18, 2026 07:28
os-zhuang added a commit that referenced this pull request Jul 18, 2026
…olver wiring (#3208)
Adds a kernel-level integration test that boots LiteKernel with a fake objectql
service (registry.getObject) + AutomationServicePlugin and proves the plugin
bridges the engine's object-schema resolver to the live registry at start():
- the wired resolver returns the object's fields + types;
- a flow registered through the running kernel doing arithmetic on a text field
emits the tier-4 advisory (captured via process.stdout);
- a sound condition stays quiet.
Locks in the production integration point that #3190's engine-level unit tests
(resolver set by hand) could not exercise. Test-only; no behavior change.
Tests: service-automation 319 (+3 e2e); full suite green.
Claude-Session: https://claude.ai/code/session_01Hnji7EEYR2mGt6pY53a8Bm
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude