Skip to content

fix(spec): mirror the objectName -> object check onto embedded actions (#7456) - #7895

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-7456-embedded-objectname-retire
Aug 12, 2026
Merged

fix(spec): mirror the objectName -> object check onto embedded actions (#7456)#7895
os-zhuang merged 1 commit into
mainfrom
claude/issue-7456-embedded-objectname-retire

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#7456

What

The third arm #7397 deliberately left open. The registered action walk in
validateCrossReferences (packages/spec/src/stack.zod.ts) applies three checks —
flow target, modal target, and objectName → declared object — but #7397's PR mirrored
only the first two onto config.objects[].actions[]. The third split the same way the
target arms did before #7397:

embedded { name: 'probe_on', type: 'script', target: 'doThing', objectName: 'probe_missing' } -> ACCEPTED
REGISTERED { name: 'probe_on', type: 'script', target: 'doThing', objectName: 'probe_missing' } -> REJECTED
"Action 'probe_on' references object 'probe_missing' which is not defined in objects."

Same action object, two authoring positions, opposite verdicts — the b/f, c/g, d/i pattern
from #7397's probe table, one key over.

Now: config.objects[].actions[] is walked and every action's objectName (when set)
is subjected to the same existence check as a registered action's. Message keeps the
registered wording from references onward and changes only the subject, same convention
already used by the flow/modal arms in this loop:

Action 'probe_on' on object 'probe_task' references object 'probe_missing' which is not
defined in objects.

Ruling this executes

#7456 filed this as an observation-class finding because mirroring the check is an
acceptance-surface change with two live readings: A — existence check (verbatim
mirror, what this PR does) vs B — consistency check (the value must equal the owning
object's own name). Quoted verbatim from the two ruling comments on the issue:

The registered-action walk already refuses a dangling objectName; the embedded arm
accepts the identical defect silently. This inherits the ruling family #7397
implemented for the flow/modal arms (silent drop on one sibling branch joins the
existing refusal set — the standing 元判据), so it does not need its own
decision-inbox slot: mirror the third check onto embedded actions. S.

Direction is Option A — existence check, verbatim mirror of the registered walk's
objectName → declared-object check, as the third arm beside #7397's flow/modal
mirrors
.

This PR implements exactly Option A. It does not foreclose B or C (retirement): an
embedded action naming a different declared object than its owner is still accepted —
only a dangling value newly refuses. Whether the key should instead be retired at this
position, or made to agree with its owner, remains open and unruled.

objectName still gives no new runtime meaning at the embedded position:
mergeActionsIntoObjects continues to build its map only from config.actions, never
from obj.actions[].objectName. This PR only makes a dangling value refused at
authoring time.

Acceptance-face narrowing / corpus census

A stack carrying a dangling embedded objectName now fails to build where it previously
built clean. Census of the shipped corpus (find . -name '*.object.ts' | xargs grep objectName, plus a broader repo-wide search filtered to examples/** and
content/docs/**) found zero files declaring objectName at the embedded position
at all, dangling or otherwise — the key is used only at the registered/top-level position
in shipped metadata today (action registries, flow bindings). No shipped stack is
affected by this change.

Tests

Extends the existing #7397 probe-table conformance file
(packages/spec/src/stack-inline-action-crossref.test.ts) with a new objectName → object (#7456) describe block rather than a new file, per the file's own stated
convention — 5 new cases:

  • rejects a dangling embedded objectName with the registered rule's wording, subject
    adjusted to the owning object (probe row k)
  • closes the b/f, c/g, d/i pattern one key over (row k/l): same verdict embedded or
    registered
  • accepts an embedded objectName naming its own owning object
  • accepts an embedded objectName naming a different declared object — pins that
    Option A is existence-only, not consistency (Option B stays open)
  • leaves an embedded action with no objectName alone — unchanged from before

Reverse verification (predicted direction: red). Reverted stack.zod.ts alone (kept
the new tests), reran the file: exactly the 2 new assertions that exercise the new check
failed, both for the right reason (refusals() returned [] instead of the expected
one-element refusal array) — not a broken fixture. Restored the implementation via
git apply from a saved patch (no git stash, per repo policy); all 47 cases in the
file pass again.

Verification

  • pnpm --filter '@objectstack/spec' build — green (prerequisite; [skill] 新 worktree 里第一次验证之前必须先 build 依赖闭包 —— AGENTS.md §9 的陈旧产物陷阱当日连咬三个 dev(假红 + 假绿两个方向) #6371)
  • pnpm --filter @objectstack/spec exec vitest run src/stack-inline-action-crossref.test.ts — 47/47 pass
  • pnpm --filter @objectstack/spec test — 379 files / 9988 tests, all pass
  • pnpm --filter @objectstack/spec typecheck — pass (tsc --noEmit, check:scripts-typecheck, check:test-typecheck)
  • pnpm check:nul-bytes — OK (7215 files scanned, no raw control bytes)
  • pnpm check:adr-anchors — OK
  • pnpm check:changeset-gate-self-tests — OK
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions — OK (24/24 self-test cases; had to build @objectstack/lint's deps first — stale dist/ trap)
  • pnpm check:docs-audit-scope — OK
  • pnpm check:driver-conformance — OK (40/40 cells)
  • pnpm check:i18n — OK (had to build @objectstack/cli first — gate's documented prerequisite)
  • pnpm check:merge-driver — OK
  • pnpm check:release-body — OK
  • pnpm check:spec-parsed-alias — OK
  • pnpm check:stack-collection-maps — OK
  • pnpm --filter @objectstack/spec check:generated — OK, all 13 generated artifacts up to date (no docs/authorable-surface regen needed by this change)
  • pnpm --filter @objectstack/spec check:authorable-surface — GREEN (baseRev lag vs the upstream anchor is the documented informational-only state, not an error)

Not run locally (CI's job, per the local-verification-scope contract): the full
lint.yml gate farm.

Changeset

.changeset/embedded-action-objectname-crossref.md@objectstack/spec minor
(acceptance-surface narrowing, so user-visible).


Generated by Claude Code

#7456)
The third arm #7397 deliberately left open. The registered action walk in
validateCrossReferences applies three checks -- flow target, modal target,
and objectName -> declared object -- but #7397's PR mirrored only the first
two onto config.objects[].actions[]. This closes the third arm (Option A,
existence check, per the 2026-08-11/12 maintainer-confirmed ruling): a
dangling objectName on an object-embedded action is now refused the same
way it already is at the registered position.
objectName still gives no new runtime meaning at the embedded position --
mergeActionsIntoObjects continues to read only config.actions -- this only
makes a dangling value refused at authoring time.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECjShwqVRAhLy15mgatGjV
@vercel

vercelBot commented Aug 12, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 12, 2026 2:42am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

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

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/permissions/system-context.mdx(via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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.

@github-actionsgithub-actionsBot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 12, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 12, 2026 02:59
@os-zhuang
os-zhuang added this pull request to the merge queueAug 12, 2026
Merged via the queue into main with commit 444de5bAug 12, 2026
27 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7456-embedded-objectname-retire branch August 12, 2026 03:16
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.

[finding] objectName on an object-embedded action is inert AND unvalidated — the third arm PR for #7397 deliberately left open

2 participants

@os-zhuang@claude