refactor(streaming): resolve-then-split strategy for @defer#1426
refactor(streaming): resolve-then-split strategy for @defer#1426jwaldrip wants to merge 65 commits into
Conversation
- Fix mix absinthe.schema.json to use schema's adapter for introspection - Fix mix absinthe.schema.sdl to use schema's adapter for directive names - Update SDL renderer to accept adapter parameter and use it for directive definitions - Ensure directive names follow naming conventions (camelCase, etc.) in generated SDL 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
When a field has no description, it now inherits the description from its referenced type during introspection. This provides better documentation for GraphQL APIs by automatically propagating type descriptions to fields. - Modified __field introspection resolver to fall back to type descriptions - Handles wrapped types (non_null, list_of) correctly by unwrapping first - Added comprehensive test coverage for various inheritance scenarios - Updated field documentation to explain the new behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Based on community feedback from PR absinthe-graphql#1373, automatic field description inheritance was not well received. The community preferred explicit field descriptions that are specific to each field's context rather than automatically inheriting from the referenced type. This commit: - Reverts the automatic inheritance behavior in introspection - Removes the associated test file - Returns to the standard field description handling 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Run mix format to fix formatting issues detected by CI. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Implement schema coordinates as defined in the GraphQL specification. Schema coordinates provide a standardized, human-readable format for referencing elements within a GraphQL schema. This implementation provides: - Coordinate generation for all schema element types - Coordinate parsing with validation - Coordinate resolution against a schema - Error helper utilities for including coordinates in messages Note: This does NOT modify the introspection schema. Schema coordinates are a string format utility, not an introspection extension. Coordinate formats: - Type: "User" - Field: "User.email" - Argument: "Query.user(id:)" - Enum Value: "Status.ACTIVE" - Directive: "@deprecated" - Directive Argument: "@deprecated(reason:)" Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the GraphQL September 2025 specification feature that allows descriptions on executable definitions (operations and fragments). Changes: - Add `description` field to Blueprint.Document.Operation struct - Add `description` field to Blueprint.Document.Fragment.Named struct - Add `description` field to Language.OperationDefinition struct - Add `description` field to Language.Fragment struct - Update parser to accept descriptions before operations and fragments - Update Blueprint.Draft conversion to preserve descriptions - Update SDL rendering to output descriptions for operations/fragments - Add comprehensive tests for the new functionality Specification: https://spec.graphql.org/September2025/#sec-Descriptions Reference: RFC absinthe-graphql#1170 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This implements Full Unicode Support as defined in GraphQL specification September 2025 (RFCs absinthe-graphql#805, absinthe-graphql#1040, absinthe-graphql#1053, absinthe-graphql#1142). Changes: - Add support for variable-width Unicode escape sequences (\u{XXXXXX}) allowing representation of all Unicode scalar values up to U+10FFFF - Add validation for Unicode scalar values in escape sequences - Add support for surrogate pair decoding in fixed-width escapes (\uXXXX) for legacy compatibility with supplementary plane characters - Properly reject invalid escape sequences: - Lone high surrogates (U+D800-U+DBFF) - Lone low surrogates (U+DC00-U+DFFF) - Out of range values (>U+10FFFF) - Surrogates in variable-width escapes - Update Parse phase to handle new Unicode escape error type - Add comprehensive test suite covering: - Basic Unicode in strings - BMP escape sequences (\uXXXX) - Extended escape sequences (\u{XXXXXX}) - Surrogate pair handling - Emoji and supplementary plane characters - Invalid escape rejection - Block strings with Unicode - Edge cases The implementation maintains full backward compatibility with existing GraphQL documents while enabling the new Unicode features. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the @semanticNonNull directive as proposed by the GraphQL nullability working group. This directive allows schema authors to indicate that a field is semantically non-null (the resolver never intentionally returns null), but may still be null due to errors. This decouples nullability from error handling, providing better developer experience for clients who want to understand which fields may be null only due to errors versus fields that may intentionally be null. Changes: - Add @semanticNonNull directive to prototype notation with levels argument - Create Absinthe.Type.SemanticNullability support module with helper functions - Add isSemanticNonNull and semanticNonNullLevels to __Field introspection - Add semantic_non_null: true/[levels] shorthand for field definitions - Comprehensive tests for all functionality Usage: ```elixir # Using directive syntax field :email, :string do directive :semantic_non_null end # Using shorthand notation field :email, :string, semantic_non_null: true field :posts, list_of(:post), semantic_non_null: [0, 1] ``` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move @semanticNonNull directive from prototype notation to a new
opt-in module Absinthe.Type.BuiltIns.SemanticNonNull.
Since @semanticNonNull is a proposed-spec feature (not yet finalized),
users must now explicitly opt-in by adding:
import_types Absinthe.Type.BuiltIns.SemanticNonNull
to their schema definition.
Also adds a new guide: guides/semantic-non-null.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This adds full TypeSystem directive support as requested in issue absinthe-graphql#1003: - Add `applied_directives` field to all Type structs (Object, Scalar, Field, Interface, Union, Enum, InputObject, Argument, Enum.Value) - Preserve applied directives through the build phase from Blueprint to final Type structs - Add `__AppliedDirective` and `__DirectiveArgument` introspection types - Add `appliedDirectives` field to `__Type`, `__Field`, `__InputValue`, and `__EnumValue` introspection types - TypeSystem directives can be applied to all spec-defined locations: SCHEMA, SCALAR, OBJECT, FIELD_DEFINITION, ARGUMENT_DEFINITION, INTERFACE, UNION, ENUM, ENUM_VALUE, INPUT_OBJECT, INPUT_FIELD_DEFINITION The directive `expand` callback continues to work for transforming type definitions at compile time, and applied directives are now visible through introspection queries. Closes absinthe-graphql#1003 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix mix absinthe.schema.json to use schema's adapter for introspection - Fix mix absinthe.schema.sdl to use schema's adapter for directive names - Update SDL renderer to accept adapter parameter and use it for directive definitions - Ensure directive names follow naming conventions (camelCase, etc.) in generated SDL 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
When a field has no description, it now inherits the description from its referenced type during introspection. This provides better documentation for GraphQL APIs by automatically propagating type descriptions to fields. - Modified __field introspection resolver to fall back to type descriptions - Handles wrapped types (non_null, list_of) correctly by unwrapping first - Added comprehensive test coverage for various inheritance scenarios - Updated field documentation to explain the new behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add @defer directive for deferred fragment execution - Add @stream directive for incremental list delivery - Implement streaming resolution phase - Add incremental response builder - Add transport abstraction layer - Implement Dataloader integration for streaming - Add error handling and resource management - Add complexity analysis for streaming operations - Add auto-optimization middleware - Add comprehensive test suite - Add performance benchmarks - Add pipeline integration hooks - Add configuration system
- Complete usage guide with examples - API reference for @defer and @stream directives - Performance optimization guidelines - Transport configuration details - Troubleshooting and monitoring guidance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix Ruby-style return statements in auto_defer_stream middleware - Correct Elixir typespec syntax in response module - Mark unused variables with underscore prefix - Remove invalid optional() syntax from typespecs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix supervisor startup handling in tests - Simplify test helpers to use standard Absinthe.run - Enable basic test execution for incremental delivery features - Address compilation issues and warnings Tests now run successfully and provide baseline for further development. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Add an `on_event` callback option to the incremental delivery system that allows sending defer/stream events to external monitoring services like Sentry, DataDog, or custom telemetry systems. The callback is invoked at each stage of incremental delivery: - `:initial` - When the initial response is sent - `:incremental` - When each deferred/streamed payload is delivered - `:complete` - When the stream completes successfully - `:error` - When an error occurs during streaming Each event includes payload data and metadata such as: - `operation_id` - Unique identifier for tracking - `path` - GraphQL path to the deferred field - `label` - Label from @defer/@stream directive - `duration_ms` - Time taken for the operation - `task_type` - `:defer` or `:stream` Example usage: Absinthe.run(query, schema, on_event: fn :error, payload, metadata -> Sentry.capture_message("GraphQL streaming error", extra: %{payload: payload, metadata: metadata} ) _, _, _ -> :ok end ) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add telemetry events for the incremental delivery transport layer to enable integration with instrumentation libraries like opentelemetry_absinthe. New telemetry events: - `[:absinthe, :incremental, :delivery, :initial]` Emitted when initial response is sent with has_next, pending_count - `[:absinthe, :incremental, :delivery, :payload]` Emitted for each @defer/@stream payload with path, label, task_type, duration, and success status - `[:absinthe, :incremental, :delivery, :complete]` Emitted when streaming completes successfully with total duration - `[:absinthe, :incremental, :delivery, :error]` Emitted on errors with reason and message All events include operation_id for correlation across spans. Events follow the same pattern as existing Absinthe telemetry events with measurements (system_time, duration) and metadata. This enables opentelemetry_absinthe and other instrumentation libraries to create proper spans for @defer/@stream operations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update the telemetry guide to document the new @defer/@stream events: - [:absinthe, :incremental, :delivery, :initial] - [:absinthe, :incremental, :delivery, :payload] - [:absinthe, :incremental, :delivery, :complete] - [:absinthe, :incremental, :delivery, :error] Includes detailed documentation of measurements and metadata for each event, plus examples for attaching handlers and using the on_event callback for custom monitoring integrations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The incremental delivery directives are still in the RFC stage and not yet part of the finalized GraphQL specification. Updated documentation to make this clear and link to the actual RFC. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move @defer and @stream directives from core built-ins to a new opt-in module Absinthe.Type.BuiltIns.IncrementalDirectives. Since @defer/@stream are draft-spec features (not yet finalized), users must now explicitly opt-in by adding: import_types Absinthe.Type.BuiltIns.IncrementalDirectives to their schema definition. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Run mix format to fix whitespace and formatting issues that were causing CI to fail. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Restore Elixir 1.19 to the CI matrix to match upstream main. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…delivery - Add Absinthe.Streaming module with shared abstractions - Add Absinthe.Streaming.Executor behaviour for pluggable task execution - Add Absinthe.Streaming.TaskExecutor as default executor (Task.async_stream) - Add Absinthe.Streaming.Delivery for pubsub incremental delivery - Enable @defer/@stream in subscriptions (automatic multi-payload delivery) - Refactor Transport to use shared TaskExecutor - Update Subscription.Local to detect and handle incremental directives - Add comprehensive backwards compatibility tests - Update guides and documentation Subscriptions with @defer/@stream now automatically deliver multiple payloads using the standard GraphQL incremental format. Existing PubSub implementations work unchanged - publish_subscription/2 is called multiple times. Custom executors (Oban, RabbitMQ, etc.) can be configured via: - Schema attribute: @streaming_executor MyApp.ObanExecutor - Context: context: %{streaming_executor: MyApp.ObanExecutor} - Application config: config :absinthe, :streaming_executor, MyApp.ObanExecutor Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…rability - Move Absinthe.Middleware.IncrementalComplexity to its own file in lib/absinthe/middleware/ - Move Absinthe.Incremental.TelemetryReporter to its own file in lib/absinthe/incremental/ - Improves code organization and makes these modules easier to find Addresses PR review feedback from @bryanjos Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
# Conflicts: # lib/absinthe/phase/debug.ex
The docstring was describing inheritance behavior that this branch removes. Reverts to the original description text. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
absinthe-graphql#1377) * update * fix introspection * add claude.md * Fix mix tasks to respect schema adapter for proper naming conventions - Fix mix absinthe.schema.json to use schema's adapter for introspection - Fix mix absinthe.schema.sdl to use schema's adapter for directive names - Update SDL renderer to accept adapter parameter and use it for directive definitions - Ensure directive names follow naming conventions (camelCase, etc.) in generated SDL 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Add field description inheritance from referenced types When a field has no description, it now inherits the description from its referenced type during introspection. This provides better documentation for GraphQL APIs by automatically propagating type descriptions to fields. - Modified __field introspection resolver to fall back to type descriptions - Handles wrapped types (non_null, list_of) correctly by unwrapping first - Added comprehensive test coverage for various inheritance scenarios - Updated field documentation to explain the new behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * gitignore local settings * fix sdl render * feat: Add @defer and @stream directive support for incremental delivery - Add @defer directive for deferred fragment execution - Add @stream directive for incremental list delivery - Implement streaming resolution phase - Add incremental response builder - Add transport abstraction layer - Implement Dataloader integration for streaming - Add error handling and resource management - Add complexity analysis for streaming operations - Add auto-optimization middleware - Add comprehensive test suite - Add performance benchmarks - Add pipeline integration hooks - Add configuration system * docs: Add comprehensive incremental delivery documentation - Complete usage guide with examples - API reference for @defer and @stream directives - Performance optimization guidelines - Transport configuration details - Troubleshooting and monitoring guidance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Correct Elixir syntax errors in incremental delivery implementation - Fix Ruby-style return statements in auto_defer_stream middleware - Correct Elixir typespec syntax in response module - Mark unused variables with underscore prefix - Remove invalid optional() syntax from typespecs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Update test infrastructure for incremental delivery - Fix supervisor startup handling in tests - Simplify test helpers to use standard Absinthe.run - Enable basic test execution for incremental delivery features - Address compilation issues and warnings Tests now run successfully and provide baseline for further development. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Complete @defer and @stream directive implementation This commit finalizes the implementation of GraphQL @defer and @stream directives for incremental delivery in Absinthe: - Fix streaming resolution phase to properly handle defer/stream flags - Update projector to gracefully handle defer/stream flags without crashing - Improve telemetry phases to handle missing blueprint context gracefully - Add comprehensive test infrastructure for incremental delivery - Create debug script for testing directive processing - Add BuiltIns module for proper directive loading The @defer and @stream directives now work correctly according to the GraphQL specification, allowing for incremental query result delivery. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Add comprehensive incremental delivery guide Add detailed guide for @defer and @stream directives following the same structure as other Absinthe feature guides. Includes: - Basic usage examples - Configuration options - Transport integration (WebSocket, SSE) - Advanced patterns (conditional, nested) - Error handling - Performance considerations - Relay integration - Testing approaches - Migration guidance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Add incremental delivery guide to documentation extras Include guides/incremental-delivery.md in the mix.exs extras list so it appears in the generated documentation alongside other guides. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Remove automatic field description inheritance Based on community feedback from PR absinthe-graphql#1373, automatic field description inheritance was not well received. The community preferred explicit field descriptions that are specific to each field's context rather than automatically inheriting from the referenced type. This commit: - Reverts the automatic inheritance behavior in introspection - Removes the associated test file - Returns to the standard field description handling 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix code formatting Run mix format to fix formatting issues detected by CI. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix dialyzer * remove elixir 1.19 * fix: resolve @defer/@stream incremental delivery issues - Fix Absinthe.Type.list?/1 undefined function by using pattern matching - Fix directive expand callbacks to return node directly (not {:ok, node}) - Add missing analyze_node clauses for Operation and Fragment.Named nodes - Fix defer depth tracking for nested defers - Fix projector to only skip __skip_initial__ flagged nodes, not all defer/stream - Update introspection tests for new @defer/@stream directives - Remove duplicate documentation files per PR review - Add comprehensive complexity analysis tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: clarify supervisor startup and dataloader integration Address review comments: - Add detailed documentation on how to start the Incremental Supervisor - Include configuration options and examples in supervisor docs - Add usage documentation for Dataloader integration - Explain how streaming-aware resolvers work with batching Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove debug test file * feat: add on_event callback for monitoring integrations Add an `on_event` callback option to the incremental delivery system that allows sending defer/stream events to external monitoring services like Sentry, DataDog, or custom telemetry systems. The callback is invoked at each stage of incremental delivery: - `:initial` - When the initial response is sent - `:incremental` - When each deferred/streamed payload is delivered - `:complete` - When the stream completes successfully - `:error` - When an error occurs during streaming Each event includes payload data and metadata such as: - `operation_id` - Unique identifier for tracking - `path` - GraphQL path to the deferred field - `label` - Label from @defer/@stream directive - `duration_ms` - Time taken for the operation - `task_type` - `:defer` or `:stream` Example usage: Absinthe.run(query, schema, on_event: fn :error, payload, metadata -> Sentry.capture_message("GraphQL streaming error", extra: %{payload: payload, metadata: metadata} ) _, _, _ -> :ok end ) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add telemetry events for incremental delivery instrumentation Add telemetry events for the incremental delivery transport layer to enable integration with instrumentation libraries like opentelemetry_absinthe. New telemetry events: - `[:absinthe, :incremental, :delivery, :initial]` Emitted when initial response is sent with has_next, pending_count - `[:absinthe, :incremental, :delivery, :payload]` Emitted for each @defer/@stream payload with path, label, task_type, duration, and success status - `[:absinthe, :incremental, :delivery, :complete]` Emitted when streaming completes successfully with total duration - `[:absinthe, :incremental, :delivery, :error]` Emitted on errors with reason and message All events include operation_id for correlation across spans. Events follow the same pattern as existing Absinthe telemetry events with measurements (system_time, duration) and metadata. This enables opentelemetry_absinthe and other instrumentation libraries to create proper spans for @defer/@stream operations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add incremental delivery telemetry documentation Update the telemetry guide to document the new @defer/@stream events: - [:absinthe, :incremental, :delivery, :initial] - [:absinthe, :incremental, :delivery, :payload] - [:absinthe, :incremental, :delivery, :complete] - [:absinthe, :incremental, :delivery, :error] Includes detailed documentation of measurements and metadata for each event, plus examples for attaching handlers and using the on_event callback for custom monitoring integrations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add incremental delivery to CHANGELOG Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: clarify @defer/@stream are draft/RFC, not finalized spec The incremental delivery directives are still in the RFC stage and not yet part of the finalized GraphQL specification. Updated documentation to make this clear and link to the actual RFC. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: make @defer/@stream directives opt-in Move @defer and @stream directives from core built-ins to a new opt-in module Absinthe.Type.BuiltIns.IncrementalDirectives. Since @defer/@stream are draft-spec features (not yet finalized), users must now explicitly opt-in by adding: import_types Absinthe.Type.BuiltIns.IncrementalDirectives to their schema definition. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: fix formatting across incremental delivery files Run mix format to fix whitespace and formatting issues that were causing CI to fail. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * ci: restore Elixir 1.19 support Restore Elixir 1.19 to the CI matrix to match upstream main. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: unify streaming architecture for subscriptions and incremental delivery - Add Absinthe.Streaming module with shared abstractions - Add Absinthe.Streaming.Executor behaviour for pluggable task execution - Add Absinthe.Streaming.TaskExecutor as default executor (Task.async_stream) - Add Absinthe.Streaming.Delivery for pubsub incremental delivery - Enable @defer/@stream in subscriptions (automatic multi-payload delivery) - Refactor Transport to use shared TaskExecutor - Update Subscription.Local to detect and handle incremental directives - Add comprehensive backwards compatibility tests - Update guides and documentation Subscriptions with @defer/@stream now automatically deliver multiple payloads using the standard GraphQL incremental format. Existing PubSub implementations work unchanged - publish_subscription/2 is called multiple times. Custom executors (Oban, RabbitMQ, etc.) can be configured via: - Schema attribute: @streaming_executor MyApp.ObanExecutor - Context: context: %{streaming_executor: MyApp.ObanExecutor} - Application config: config :absinthe, :streaming_executor, MyApp.ObanExecutor Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: extract middleware and telemetry modules for better discoverability - Move Absinthe.Middleware.IncrementalComplexity to its own file in lib/absinthe/middleware/ - Move Absinthe.Incremental.TelemetryReporter to its own file in lib/absinthe/incremental/ - Improves code organization and makes these modules easier to find Addresses PR review feedback from @bryanjos Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…to gigsmart/integration
…igsmart/integration
…gigsmart/integration
…to gigsmart/integration # Conflicts: # lib/absinthe/type/built_ins/introspection.ex
- Fix Phase.Schema to resolve imported directives from blueprint definitions, not just the prototype schema. This allows import_directives to work for applied directives. - Fix ErrorHelpers clause ordering so :directive atom patterns match before generic patterns. - Fix escaped interpolation in ErrorHelpers @moduledoc. - Fix coordinate test to use RootQueryType (default query type name). - Fix semantic_nullability tests to use import_directives. - Remove semanticNonNull from introspection tests where fixture schemas don't import it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The memory limit check (max_memory_mb) was rejecting @defer/@stream operations based on total BEAM VM memory, which includes all loaded code, ETS tables, connection pools, etc. The BEAM naturally sits above the 500MB default on any non-trivial application, causing all incremental delivery to be silently rejected. Stream data is ephemeral — it's resolved, written to the transport, and GC'd. Blocking streams doesn't free memory, it just breaks responses. Concurrent stream count (max_concurrent_streams) is the correct backpressure mechanism and is preserved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # lib/absinthe/incremental/resource_manager.ex
…lit strategy Replace complex sub-blueprint re-resolution with a simpler approach: 1. Run standard resolution (resolves everything including @defer fields) 2. Collect @defer metadata (label, field_names, parent_path) via AST walk 3. Store in streaming context for the transport layer to split The transport layer (absinthe_plug) handles splitting the final result into initial/incremental SSE payloads after the Result phase runs. Fixes: CaseClauseError in Projector.do_collect (nil selections), KeyError in build_sub_blueprint (:path not in Execution struct), and broken path tracking across sibling nodes in prewalk.
|
Hey @jwaldrip I think we are rapidly approaching an impasse here. I have not received any communication public or private on #1377 which I had to unship due to a mixture of CI failures, AI fragments, and a general lack of human oversight. This PR clearly builds on the previous work and doesn't even realize I unshipped it. I am more than happy to have a larger conversation here given the important areas of work at hand here but I want to be very clear that PRs like this are entirely unsuitable. |
|
@benwilson512 I disagree with many of your assertions here and the reasoning to unship the original code. It DID go through community human review beyond the review I gave it with my own eyes and additional back pressure from claude. I understand you are the maintainer of this project. But @gigsmart will maintain their own fork and stop contributing to the main repo. The review cycle is too long, and frankly our direction on LLM and our internal advancements on such don't align with your philosophy. Thank you for your original contributions and I hope to see some advancements come to the core repo in addition to our fork. |
Summary
StreamingResolutionto resolve everything in one pass (standard resolution), then store@defermetadata in the streaming context:pathkey in Execution struct, broken path tracking across siblings in prewalk)What changed
lib/absinthe/phase/document/execution/streaming_resolution.ex— full rewriteOld approach: skip deferred nodes during initial resolution → re-resolve them later via sub-blueprints → broken
New approach: resolve everything → collect defer metadata via AST walk → let plug split the result
Follow-up commit addresses Bugbot review feedback:
Fragment.Spreadnodes (not justFragment.Inline) when walking for@defer, including traversal of named fragmentsdeferred_fragments,streamed_fields,deferred_tasks,stream_tasks) on__streaming__context so downstreamAbsinthe.Incremental.*consumers don't raiseKeyErrorTest plan
@deferquery returns initial payload without deferred fields + incremental payload with deferred data@defer) continue to work unchangedpending/hasNext), incremental, complete@deferon fragment spreads (...FragmentName @defer) is honored@deferon inline fragments continues to workDepends on
Upstream note
Companion to gigsmart#8. Original author: @juscyllan.