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 bridge AutomationEngine.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

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 18, 2026 8:15am

Request Review

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

github-actions Bot 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 main July 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-zhuang force-pushed the claude/flow-registration-schema-aware-validation branch from 79f41ea to adf2015 Compare July 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 main Jul 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants