Skip to content

feat(gateway)!: share one stream configuration and move the test harness out of the gateway - #54

Merged
sunib merged 2 commits into
docs/proposal-0009-stream-editor-separationfrom
feat/proposal-0010-gateway-api-cleanup
Oct 5, 2026
Merged

sunib merged 2 commits into
docs/proposal-0009-stream-editor-separationfrom
feat/proposal-0010-gateway-api-cleanup

Conversation

@sunib

@sunib sunib commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Stacked on #53. This PR is based on docs/proposal-0009-stream-editor-separation, which adds proposal 0010. Once #53 merges, it retargets to main. It adds only the two feat(gateway)! commits.

Implements proposal 0010 (Go gateway API cleanup) as its two planned changes. Each commit builds and is fully migrated on its own. Authorization, projection, bounded HTTP delivery, the shared-watch lifecycle and v1 wire behavior are unchanged.

Change 1: one configuration, one stream method each, one constructor (f73fc47)

  • New StreamConfig holds the settings every serving path needs: Authorizer, Clients, Projections, Ordering, Observer, Diagnostics, HeartbeatInterval, WriteTimeout, ReauthorizationInterval and ReauthorizationTimeout. Options (plus Principal and Scopes) and Gateway both embed it. Handler copies one value instead of mapping fields, and Gateway.Auth becomes Authorizer on both paths.
  • Projection is removed. A nil Projections grants only ProjectionFull; a host with one view uses StaticProjection.
  • ServeStream(w, r, principal, scope, requested) and Stream(ctx, principal, scope, requested, sink) replace the default/…Projection pairs. NewSharedBackend(upstream, SharedOptions) replaces the two constructors.
  • Validation is unchanged. HTTP serving still refuses a negative WriteTimeout, and timed checks without one, before any I/O. Stream still leaves generic sinks to the host.
  • The strict-ordering refusal now names StreamConfig.Ordering, so one golden line changes, in message prose only (see Golden output).

Change 2: the conformance harness leaves the production package (8bc56df)

  • Fixture, WatchOp, FixtureEvent, Corpus, LoadCorpus and ScriptedBackend move to gateway/internal/conformance. The relative-path LoadConformance is removed; the replay server and the tests name the corpus directory. package gateway no longer imports the harness, nor os/path/filepath directly.
  • The replay server and the tests split connection scripts with one function, conformance.Connections, instead of two copies that differed on empty segments. No fixture has an empty segment, so served bytes are unchanged.
  • Fixture-driven conformance, golden and bookkeeping-suppression tests move to package gateway_test. Private implementation tests stay in package gateway.
  • SSESink.Comment becomes a private comment, which the heartbeat now uses (same bytes). The heartbeat default becomes private, and StreamConfig documents the 20 seconds. Scope.Query moves into the scope conformance test. ScopeFromQuery and the canonical-query checks are unchanged.
  • The fixtures task lists the harness as a source of the goldens.

Deliberately kept, per the proposal: SLOW_CONSUMER, the Sink/Stream/SSE encoding seams, OrderingLenient, and Event.Target.

Breaking changes

  • Composite literals set the shared settings inside StreamConfig: gateway.StreamConfig{…}:
    gateway.Options{
        Principal: userFromSession,
        Scopes:    allowedScopes,
        StreamConfig: gateway.StreamConfig{
            Authorizer:   authorizeScope,
            Clients:      clientsForUser,
            Projections:  gateway.StaticProjection(gateway.ProjectionSpec),
            WriteTimeout: 5 * time.Second,
        },
    }
    Assignments such as opts.Authorizer = … keep working through field promotion.
  • Gateway.Auth → Authorizer. Projection: p → Projections: gateway.StaticProjection(p), or nil for ProjectionFull.
  • ServeStreamProjection/StreamProjection are removed. ServeStream and Stream take the requested projection; pass "" for the default view.
  • NewSharedBackendWithOptions is removed. Use NewSharedBackend(upstream, gateway.SharedOptions{…}).
  • Removed exports: Fixture, WatchOp, FixtureEvent, Corpus, LoadCorpus, LoadConformance, ScriptedBackend, NewScriptedBackend, SSESink.Comment, the HeartbeatInterval constant and Scope.Query.

Golden output

conformance/gen/sse/resourceversion-unorderable.sse changes in exactly one place: the error message now says Set StreamConfig.Ordering = OrderingLenient instead of Set Gateway.Ordering = …. The proposal asks for that message to name the shared setting. Code, terminal, sequence and framing are byte-identical, and both suites deliberately compare error messages loosely. Every other golden, protocol.json, fixtures.json and scopes.json is unchanged. After change 2, the moved harness regenerates every golden byte-identically, including one deleted and recreated as a check.

Verification

task verify passes on 8bc56df: fixtures-check, lint (Go vet and golangci-lint in both modules, TypeScript, Biome, actionlint, hadolint), test (both Go modules with -race, client 129/129, Vue 2/2), release-rehearsal, e2e-wire (14 fixtures), e2e-browser (20/20) and pack-client.

New tests cover:

  • a nil projection policy redacting Secrets and refusing other views before a watch opens;
  • a dynamic policy deciding at opening and on every cycle (timed checks were already covered);
  • Handler serving with its whole StreamConfig;
  • Options and Gateway sharing one StreamConfig, with no duplicate setting names.

The first two were checked by breaking the implementation on purpose: a raw default policy, and a Handler copying a subset of the config.

Not available: no krm-foyer (or other host) source is checked out here, so host imports of the removed APIs could not be inventoried. No cluster tasks were run; the proposal makes no capacity claim and requires no new cluster run.

BREAKING CHANGE: Options and Gateway embed StreamConfig, so composite literals set Authorizer, Clients, Projections, Ordering, Observer, Diagnostics, HeartbeatInterval, WriteTimeout and the reauthorization settings inside StreamConfig: gateway.StreamConfig{...}. Gateway.Auth is renamed Authorizer. The Projection field is removed: use Projections: gateway.StaticProjection(p), or leave it nil for ProjectionFull. ServeStream(w, r, principal, scope, requested) and Stream(ctx, principal, scope, requested, sink) replace ServeStreamProjection and StreamProjection; pass "" for the default view. NewSharedBackend(upstream, options) replaces NewSharedBackendWithOptions. The repository test harness (Fixture, WatchOp, FixtureEvent, Corpus, LoadCorpus, LoadConformance, ScriptedBackend, NewScriptedBackend), SSESink.Comment, the HeartbeatInterval constant and Scope.Query are no longer exported.

🤖 Generated with Claude Code

sunib and others added 2 commits October 4, 2026 20:35
…try points

Implement change 1 of proposal 0010.

- StreamConfig holds every setting a stream needs however it is
  served: Authorizer, Clients, Projections, Ordering, Observer,
  Diagnostics, HeartbeatInterval, WriteTimeout, ReauthorizationInterval
  and ReauthorizationTimeout. Options and Gateway embed it, so each
  setting has one name and Handler copies one value instead of mapping
  fields. Gateway.Auth is now Authorizer on both paths.
- One projection field. Projection is removed; nil Projections grants
  only ProjectionFull, and a host with one view uses StaticProjection.
- ServeStream and Stream take the requested projection; the
  ServeStreamProjection and StreamProjection variants are removed.
  NewSharedBackend takes SharedOptions; NewSharedBackendWithOptions is
  removed.
- Validation is unchanged: HTTP serving still refuses a negative
  WriteTimeout and timed checks without one before any I/O, and Stream
  still leaves generic sinks to the host.
- The strict-ordering refusal names StreamConfig.Ordering, so its one
  golden transcript line changes in message prose only.
- Tests cover a nil policy redacting Secrets and refusing other views, a
  dynamic policy deciding at opening and on every cycle, Handler serving
  with its whole StreamConfig, and the two entry points sharing it.
  Callers, the replay server, kube examples and guides are migrated.

BREAKING CHANGE: Options and Gateway embed StreamConfig, so composite literals set Authorizer, Clients, Projections, Ordering, Observer, Diagnostics, HeartbeatInterval, WriteTimeout and the reauthorization settings inside StreamConfig: gateway.StreamConfig{...}. Gateway.Auth is renamed Authorizer. The Projection field is removed: use Projections: gateway.StaticProjection(p), or leave it nil for ProjectionFull. ServeStream(w, r, principal, scope, requested) and Stream(ctx, principal, scope, requested, sink) replace ServeStreamProjection and StreamProjection; pass "" for the default view. NewSharedBackend(upstream, options) replaces NewSharedBackendWithOptions; pass gateway.SharedOptions{} for the defaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ckage

Implement change 2 of proposal 0010.

- The fixture loader and scripted backend move from package gateway to
  gateway/internal/conformance: Fixture, WatchOp, FixtureEvent, Corpus,
  LoadCorpus and ScriptedBackend. The production gateway no longer
  imports it, so serving a stream never loads a corpus from disk.
  LoadConformance, the relative-path convenience loader, is removed;
  the replay server and the tests name the corpus directory.
- The replay server and the tests split connection scripts with one
  function, conformance.Connections, instead of two copies.
- Fixture-driven conformance, golden and bookkeeping-suppression tests
  move to package gateway_test, which can import the harness without a
  cycle. Private implementation tests stay in package gateway. Goldens
  are still written through the production SSE sink and regenerate
  byte-identically.
- SSESink.Comment becomes a private helper, now also used by the
  heartbeat, which keeps writing the same bytes. The heartbeat default
  becomes private; StreamConfig documents the 20-second default.
- Scope.Query, used only by a conformance test, moves into that test.
  ScopeFromQuery and the canonical query checks are unchanged.
- The fixtures task lists the harness as a source of the goldens.

BREAKING CHANGE: gateway no longer exports Fixture, WatchOp, FixtureEvent, Corpus, LoadCorpus, LoadConformance, ScriptedBackend or NewScriptedBackend; they were repository test harness. SSESink.Comment, the HeartbeatInterval constant and Scope.Query are removed: set StreamConfig.HeartbeatInterval (zero means 20 seconds), and build a scope's query string from its fields in the documented order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 19 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8dfdcf8f-2701-4e02-9f25-3dc46af3aeb5
📥 Commits

Reviewing files that changed from the base of the PR and between 42c745c and 8bc56df.

⛔ Files ignored due to path filters (1)
  • conformance/gen/sse/resourceversion-unorderable.sse is excluded by !**/gen/**
📒 Files selected for processing (36)
  • README.md
  • Taskfile.yml
  • docs/adopting.md
  • docs/auth.md
  • docs/operations.md
  • gateway/README.md
  • gateway/auth_test.go
  • gateway/cmd/replay/main.go
  • gateway/config.go
  • gateway/config_test.go
  • gateway/conformance_test.go
  • gateway/golden_test.go
  • gateway/handler.go
  • gateway/handler_test.go
  • gateway/http_config_test.go
  • gateway/internal/conformance/corpus.go
  • gateway/internal/conformance/scripted.go
  • gateway/kube/authz.go
  • gateway/kube/authz_test.go
  • gateway/kube/e2e_test.go
  • gateway/kube/examples/sharedstream/handler.go
  • gateway/lifecycle_test.go
  • gateway/observe.go
  • gateway/reauthorize.go
  • gateway/reauthorize_test.go
  • gateway/scope.go
  • gateway/scope_conformance_test.go
  • gateway/shared.go
  • gateway/shared_bigcache_test.go
  • gateway/shared_open_test.go
  • gateway/shared_test.go
  • gateway/sse.go
  • gateway/sse_test.go
  • gateway/stream.go
  • gateway/stream_conformance_test.go
  • gateway/stream_test.go
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant