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.
@github-project-automation github-project-automation Bot moved this to Discussion Ongoing in PR Backlog Aug 1, 2026
@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

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

1 participant