Skip to content

REST GET silently omits @computed fields from responses (computed getters are non-enumerable) #1484

Description

@kriszyp

REST GET responses (collection scan and single-record point-read) silently omit @computed fields, while ops search_by_value(get_attributes) and SQL SELECT */SELECT computedField/aggregates all return them with correct values.

Root: @computed getters are installed as non-enumerable properties on structPrototype — resources/graphql.ts:229 only sets enumerable: true when the separate @enumerable directive is applied, so a plain @computed field defaults to non-enumerable. REST serialization uses JSON.stringify, which walks only own-enumerable properties → the computed getter is invisible. The ops path iterates the attributes[] array explicitly, so it always includes computed fields.

Workaround (predicted): annotate the computed field with @enumerable.

Fix: make @computed fields enumerable by default (or have the REST serializer include computed getters explicitly) so REST GET matches ops/SQL.

Other @computed semantics are correct: computed-on-read (no stale value), index materialized at write with no staleness under source-field churn, direct writes to a computed field rejected 400, both engines identical.

Severity: medium — silent omission on the most common read surface (REST clients never see the computed value).

Repro: npm run test:integration -- "integrationTests/qa-scratch/qa363-computed.test.ts"

— filed by KrAIs (Claude) on Kris's behalf (qa-explorer campaign, main @ 28db4fd v5.1.12)

Activity

  1. kriszyp commented on Jun 29, 2026

    @kriszyp
    MemberAuthor

    Extending this: the same non-enumerable @computed getter root also drops computed fields from change-event subscription payloads across all three transports (SSE, MQTT, WebSocket), not just REST GET.

    QA repro (harper main f447404 / v5.1.13): a User table with firstName, lastName, and fullName @computed(...). Subscribe, then mutate:

    • SSE/WS change-event value omits fullName on insert, on a source-field PATCH, and on an unrelated-field PATCH (the event fires, fullName is simply absent — not stale, not recomputed).
    • MQTT delivers the bare record {id,firstName,lastName} — also no fullName.
    • Meanwhile ops search_by_value and SQL SELECT return fullName:"Pro Be" correctly, proving the value materializes.

    So the omission is confined to the two serializers that walk own-enumerable props — REST-GET JSON.stringify and the change-event serializer. GraphQL resolves each requested field explicitly, so it already includes computed fields and needs no change.

    Net: the fix here (make @computed enumerable by default, or have these serializers explicitly include computed getters) should cover REST GET and the SSE/MQTT/WS subscription payloads in one shot. Most likely to bite reactive-UI / dashboard clients that subscribe expecting derived fields.

    Repro tests: qa369-computed-subscription.test.ts (SSE), qa371-computed-sub-transports.test.ts (MQTT+WS).

    — from Harper exploratory QA (KrAIs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions