Skip to content

fix(httpapi): reuse named schemas across response statuses - #6837

Open
aryasaatvik wants to merge 2 commits into
Effect-TS:mainfrom
aryasaatvik:fix/httpapi-status-representation-identity
Open

fix(httpapi): reuse named schemas across response statuses#6837
aryasaatvik wants to merge 2 commits into
Effect-TS:mainfrom
aryasaatvik:fix/httpapi-status-representation-identity

Conversation

@aryasaatvik

@aryasaatvik aryasaatvik commented Aug 1, 2026

Copy link
Copy Markdown

Summary

Reuse a named schema across response statuses without emitting duplicate OpenAPI components.

HttpApiSchema.status now stores status metadata in key context, while representation identity recognizes rebuilt containers from the same annotated declaration.

Before / After

const Widget = Schema.Struct({
  id: Schema.String,
  metadata: Schema.Record(Schema.String, Schema.Unknown)
}).annotate({ identifier: "Widget" })

const CreatedWidget = Widget.pipe(HttpApiSchema.status(201))
Response Before After
GET 200 Widget Widget
POST 201 Widget_1 Widget

Changes

  • Store httpApiStatus in key context, with annotation fallback for declaration-site statuses such as HttpApiError.
  • Compare rebuilt property and index-signature containers by contents when they share the same annotations object.
  • Preserve reference identity for anonymous schemas and separately annotated declarations.

Tests

  • Added OpenAPI regressions for named schemas reused with status, including schemas containing Unknown.
  • Added a representation-level regression for context-only copies whose codec derivation rebuilds containers.
  • Passed the HTTP API and schema test suites: 2,220 tests.
  • Typecheck and lint clean.

HttpApiSchema.status annotated the schema with httpApiStatus, forking the
AST while the fork kept its identifier. A named schema reused with a
non-default status then published duplicate OpenAPI components for one
declared name (previously: Duplicate identifier throw).

The status describes how one endpoint uses the schema, not what the
schema is, so it now rides the AST key context — which representation
identity already excludes — via annotateKey. Declaration-site statuses
(the HttpApiError classes) keep working through the annotation fallback.
@changeset-bot

changeset-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 571d0c7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
effect Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@effect-slopcop effect-slopcop Bot added 4.0 bug Something isn't working labels Aug 1, 2026
@aryasaatvik aryasaatvik changed the title Carry httpApiStatus in key context so named schemas don't fork Fix HttpApiSchema.status forking named schemas into duplicate identifiers Aug 1, 2026
@aryasaatvik aryasaatvik changed the title Fix HttpApiSchema.status forking named schemas into duplicate identifiers fix(httpapi): prevent HttpApiSchema.status from forking named schemas into duplicate identifiers Aug 1, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Moved httpApiStatus to key contextstatus() now uses annotateKey so the status code is excluded from representation identity; a named schema reused with different status codes stays one OpenAPI component.
  • Context-first resolution with annotation fallbackresolveHttpApiStatus checks context.annotations first, then the annotation resolver, so HttpApiError classes (which use httpApiStatus as a regular annotation) keep working without changes.
  • Test covering the exact bug — validates that a Widget schema used with both default 200 and status(201) produces a single Widget component referenced by both responses.

The change is minimal (3 lines of behavioral code), the fallback is unambiguous, and all internal consumers go through resolveHttpApiStatus — no missed paths.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) (Kimi K2 not used — the program covers this model; add its provider key to run your pick) | 𝕏

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
basic.ts 6.63 KB 6.63 KB 0.00 KB (0.00%)
batching.ts 9.42 KB 9.42 KB 0.00 KB (0.00%)
brand.ts 6.31 KB 6.31 KB 0.00 KB (0.00%)
cache.ts 10.16 KB 10.16 KB 0.00 KB (0.00%)
config.ts 20.32 KB 20.32 KB 0.00 KB (0.00%)
differ.ts 19.93 KB 19.93 KB 0.00 KB (0.00%)
http-client.ts 21.02 KB 21.02 KB 0.00 KB (0.00%)
logger.ts 10.32 KB 10.32 KB 0.00 KB (0.00%)
metric.ts 8.55 KB 8.55 KB 0.00 KB (0.00%)
optic.ts 7.33 KB 7.33 KB 0.00 KB (0.00%)
pubsub.ts 14.46 KB 14.46 KB 0.00 KB (0.00%)
queue.ts 11.13 KB 11.13 KB 0.00 KB (0.00%)
schedule.ts 10.31 KB 10.31 KB 0.00 KB (0.00%)
schema-class.ts 18.86 KB 18.86 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 28.67 KB 28.67 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 25.10 KB 24.99 KB +0.11 KB (+0.45%)
schema-string-transformation.ts 12.99 KB 12.99 KB 0.00 KB (0.00%)
schema-string.ts 10.65 KB 10.65 KB 0.00 KB (0.00%)
schema-template-literal.ts 14.85 KB 14.85 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 21.66 KB 21.66 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 24.18 KB 24.08 KB +0.11 KB (+0.44%)
schema-toCodecJson.ts 18.91 KB 18.91 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 18.73 KB 18.73 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.59 KB 18.59 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 22.45 KB 22.33 KB +0.12 KB (+0.52%)
schema-toRepresentation.ts 19.36 KB 19.25 KB +0.11 KB (+0.58%)
schema.ts 18.12 KB 18.12 KB 0.00 KB (0.00%)
stm.ts 12.11 KB 12.11 KB 0.00 KB (0.00%)
stream.ts 9.37 KB 9.37 KB 0.00 KB (0.00%)

…ation

A memoized AST derivation (toCodecJson) rebuilds a node whenever any child
changes - e.g. Unknown lowering to Json - allocating fresh property-signature
wrappers and arrays per top-level input. Two ASTs that differ only in their
key context (a named schema and its HttpApiSchema.status copy) are separate
derivation inputs, so their rebuilt containers can never be reference-equal
and representation identity split them into Widget and Widget_1.

Container wrappers are pure structure with no identity of their own. When two
ASTs hold the same annotations object - the token of one user declaration -
their container slots now compare by contents instead of by reference.
Anonymous nodes and nodes with different annotation objects keep pure
reference identity, so referentially distinct declarations still suffix.
@aryasaatvik
aryasaatvik force-pushed the fix/httpapi-status-representation-identity branch from cae36dc to 571d0c7 Compare August 1, 2026 15:49
@aryasaatvik aryasaatvik changed the title fix(httpapi): prevent HttpApiSchema.status from forking named schemas into duplicate identifiers fix(schema): keep one OpenAPI component for a named schema reused with HttpApiSchema.status Aug 1, 2026
@aryasaatvik aryasaatvik changed the title fix(schema): keep one OpenAPI component for a named schema reused with HttpApiSchema.status fix(httpapi): reuse named schemas across response statuses Aug 1, 2026
@tim-smart
tim-smart requested a review from gcanti August 3, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0 bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant