Skip to content

feat(spec,cli): validate dataset measure aggregation by field semantics#2208

Merged
xuyushun441-sys merged 1 commit into
mainfrom
fix/aggregation-coherence
Jun 22, 2026
Merged

feat(spec,cli): validate dataset measure aggregation by field semantics#2208
xuyushun441-sys merged 1 commit into
mainfrom
fix/aggregation-coherence

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Why

A dataset measure that SUMs a percent/rate field produces a meaningless total (it routinely exceeds 100%) — rates must AVG. Nothing at author time knew this, so a hand-authored or AI-authored dataset could declare a win-probability measure as sum and pass os validate/compile clean. (Surfaced on a live AI-built CRM dashboard: a probability column summed to 145%, 200%.)

What

  • @objectstack/spec/data — new aggregation-policy (the single source of truth for field→aggregation semantics, shared by authoring and validation so they can't drift):
    • defaultAggregateFor(fieldType) — rates (percent) AVG, additive amounts SUM.
    • isIncoherentAggregate(aggregate, fieldType) — true only for genuinely meaningless cases (today: SUM/count_distinct of a percent); never raises when the type is unknown.
  • @objectstack/cli validateWidgetBindings — new measure-aggregate-incoherent advisory: checks every dataset's measures against its bound object's field types and flags an incoherent aggregation. Runs at validate/compile/build through the existing widget-binding pass; never false-positives without the object's field types (e.g. cross-package datasets).

Notes

  • Severity is warning (the page still renders, the number is just wrong) — suppressible per measure via suppressWarnings: ['measure-aggregate-incoherent'].
  • This is the open-mechanism half of the fix. The AI build's generator fix (cloud) derives the correct aggregation up front; this gives the same guarantee to hand-authored apps and is where a cloud follow-up will consume isIncoherentAggregate to replace its local copy.

Tests

  • spec: aggregation-policy.test.ts (policy + coherence matrix).
  • cli: validate-widget-bindings.test.ts — sum-on-percent flagged, avg clean, currency-sum clean, count_distinct-of-percent flagged, no-objects no-op. 33/33 in that file; 6612 spec tests green.

🤖 Generated with Claude Code

A measure that SUMs a percentage/rate field produces a meaningless total (it
can exceed 100%); rates must AVG. Authoring tools and `os validate` had no
notion of this, so a hand-authored — or AI-authored — dataset could summon a
"win-probability" measure as SUM and pass every check.

- @objectstack/spec/data: new aggregation-policy — `defaultAggregateFor`
  (rates AVG, amounts SUM) and `isIncoherentAggregate`. The single source of
  truth for field→aggregation semantics, shared by authoring (dataset
  derivation) and validation so the two cannot drift.
- @objectstack/cli validateWidgetBindings: new `measure-aggregate-incoherent`
  advisory — checks every dataset's measures against its object's field types
  and flags SUM/count_distinct of a percent field. Runs at
  validate/compile/build through the existing widget-binding pass; never
  false-positives when the object's field types are unknown.

Tests: spec policy unit tests + cli validator cases (sum-on-percent flagged,
avg clean, currency-sum clean, no-objects no-op, count_distinct flagged).
@vercel

vercel Bot commented Jun 22, 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 22, 2026 1:17pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/spec.

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

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/cli, packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/cli, @objectstack/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 packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/spec)
  • content/docs/guides/authentication.mdx (via @objectstack/cli)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/cli, packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/spec)
  • content/docs/guides/project-scoping.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/cli, packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via packages/cli, @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/guides/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/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 packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

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.

@xuyushun441-sys
xuyushun441-sys merged commit 97ba590 into main Jun 22, 2026
16 of 17 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the fix/aggregation-coherence branch June 22, 2026 13:19
xuyushun441-sys added a commit that referenced this pull request Jun 22, 2026
…rts (#2209)

#2208 added three @objectstack/spec/data exports (defaultAggregateFor,
isIncoherentAggregate, MEASURE_FIELD_TYPES) but did not regenerate the public
API-surface snapshot, so the `check:api-surface` gate failed on main. Intentional
addition: 0 breaking, 3 added.

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
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.

2 participants