Skip to content

fix(automation): accept config.fieldValues as an alias for create/update_record fields#2419

Closed
os-zhuang wants to merge 1 commit into
mainfrom
fix/automation-crud-fields-alias
Closed

fix(automation): accept config.fieldValues as an alias for create/update_record fields#2419
os-zhuang wants to merge 1 commit into
mainfrom
fix/automation-crud-fields-alias

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Problem

The create_record / update_record automation node executors read their write map from config.fields (packages/services/service-automation/src/builtin/crud-nodes.ts). But the AI build agent — and some hand-authored/legacy flows — emit the write map under config.fieldValues. When the keys mismatch, interpolate(cfg.fields ?? {}, …) resolves to an empty map, so the node inserts/updates a blank record; required-field validation then fails and the automation silently does nothing.

This is the framework half of "AI-built record-change flows don't write end-to-end". The runtime/trigger half (flows never fired) was fixed in cloud#686; the authoring-convention half is fixed in the paired cloud PR (the skill now emits fields). This PR makes the executor defensively tolerant so flows already stored under fieldValues keep working without re-authoring.

Change

Alias the write-map key, mirroring the executor's existing cfg.filter ?? cfg.filters and cfg.objectName ?? cfg.object tolerance right alongside:

const fields = interpolate(cfg.fields ?? cfg.fieldValues ?? {}, variables, context);

fields wins when both are present. Applied to both create_record and update_record.

Tests

  • crud-output-var.test.ts — proves the alias through the real AutomationEngine (create + update, with {var.id} interpolation), plus a fields-wins-over-fieldValues precedence case.
  • record-change-integration.test.ts — boots a real kernel (ObjectQL + automation + record-change trigger + data engine) and drives the documented scenario "customer status → lost auto-creates a linked follow-up" end to end: a live data.update fires the record-after-update hook, the flow's create_record writes a follow-up that is correctly linked ({record.id} → the triggering row's id) and populated ({TODAY()} → today's date). Asserted for both the canonical fields key and the legacy fieldValues alias.

Full service-automation (224) and trigger-record-change (22) suites green.

🤖 Generated with Claude Code

…pdate_record `fields`

The create_record / update_record node executors read the write map from
`config.fields`, but the AI build agent (and some legacy flows) author it under
`config.fieldValues`. When the keys mismatch the executor interpolates an empty
map and inserts/updates a blank record — required-field validation then fails and
the automation silently does nothing.

Alias `cfg.fields ?? cfg.fieldValues`, mirroring the existing
`cfg.filter ?? cfg.filters` / `cfg.objectName ?? cfg.object` tolerance, so both
authoring conventions write real data (`fields` wins when both are present).

Tests: crud-output-var proves the alias through the real AutomationEngine (create
+ update, with interpolation); record-change-integration proves the full
"status→lost auto-creates a linked follow-up" scenario end-to-end through the real
kernel + record-change trigger + data engine, for both `fields` and `fieldValues`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 28, 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 Jun 28, 2026 10:07am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): packages/services, packages/triggers.

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

  • content/docs/guides/packages.mdx (via packages/services)
  • content/docs/guides/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/index.mdx (via packages/services)
  • content/docs/guides/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/protocol/objectos/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.

@os-zhuang

Copy link
Copy Markdown
Contributor Author

Closing per design review: the right fix is to correct the metadata at the source (cloud#688 skill + lint) and keep a single strict config.fields contract — not to teach the runtime executor to tolerate the non-contract fieldValues key. The 'follow the existing cfg.filter ?? cfg.filters precedent' rationale doesn't hold up: those aliases are debt, not a pattern to extend. Local/test AI-generated metadata under the old key is disposable and won't be migrated. A separate task will audit the existing runtime key/case aliases in the framework.

@os-zhuang os-zhuang closed this Jun 28, 2026
@xuyushun441-sys
xuyushun441-sys deleted the fix/automation-crud-fields-alias branch June 28, 2026 10:19
os-zhuang added a commit that referenced this pull request Jul 13, 2026
Refreshes the bundled Console to objectui main including #2419, which
propagates the action-param `visible` predicate through resolveActionParams.

Completes the create-user phone fix end to end: the console now honors the
served `visible: 'features.phoneNumber == true'` predicate on the create_user
phoneNumber param, hiding the field when the phoneNumber auth plugin is off
instead of offering a field the default backend rejects.

objectui range: 9138e68413f3...2fb38edbeb12

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant