connectrpc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +501 -0
- data/docs/design.md +504 -0
- data/docs/development.md +566 -0
- data/docs/grpc-web.md +165 -0
- data/docs/grpc.md +75 -0
- data/docs/rbs.md +469 -0
- data/docs/streaming.md +251 -0
- data/exe/protoc-gen-connectrpc-ruby +23 -0
- data/lib/connectrpc/bindings/descriptors/status.bin +15 -0
- data/lib/connectrpc/bindings/google_protobuf.rb +92 -0
- data/lib/connectrpc/cancellation.rb +220 -0
- data/lib/connectrpc/client.rb +260 -0
- data/lib/connectrpc/compression.rb +120 -0
- data/lib/connectrpc/deadline.rb +81 -0
- data/lib/connectrpc/error.rb +72 -0
- data/lib/connectrpc/generator/names.rb +105 -0
- data/lib/connectrpc/generator/rbs_renderer.rb +93 -0
- data/lib/connectrpc/generator/renderer.rb +115 -0
- data/lib/connectrpc/generator/runtime_names.rb +84 -0
- data/lib/connectrpc/generator/schema.rb +218 -0
- data/lib/connectrpc/generator/streaming_methods.rb +29 -0
- data/lib/connectrpc/generator.rb +42 -0
- data/lib/connectrpc/get_query.rb +159 -0
- data/lib/connectrpc/grpc.rb +200 -0
- data/lib/connectrpc/grpc_client.rb +23 -0
- data/lib/connectrpc/grpc_server.rb +158 -0
- data/lib/connectrpc/grpc_web.rb +131 -0
- data/lib/connectrpc/grpc_web_cors.rb +135 -0
- data/lib/connectrpc/grpc_web_io.rb +156 -0
- data/lib/connectrpc/grpc_web_server.rb +207 -0
- data/lib/connectrpc/instrumentation.rb +216 -0
- data/lib/connectrpc/message_io.rb +47 -0
- data/lib/connectrpc/metadata.rb +105 -0
- data/lib/connectrpc/method.rb +68 -0
- data/lib/connectrpc/protocol.rb +189 -0
- data/lib/connectrpc/server.rb +398 -0
- data/lib/connectrpc/streaming/client.rb +104 -0
- data/lib/connectrpc/streaming/client_execution.rb +87 -0
- data/lib/connectrpc/streaming/client_scope.rb +105 -0
- data/lib/connectrpc/streaming/framing.rb +123 -0
- data/lib/connectrpc/streaming/framing_io.rb +61 -0
- data/lib/connectrpc/streaming/method.rb +33 -0
- data/lib/connectrpc/streaming/server.rb +122 -0
- data/lib/connectrpc/streaming/server_execution.rb +88 -0
- data/lib/connectrpc/streaming/server_terminal.rb +70 -0
- data/lib/connectrpc/streaming/session.rb +143 -0
- data/lib/connectrpc/streaming/session_completion.rb +134 -0
- data/lib/connectrpc/streaming/session_io.rb +107 -0
- data/lib/connectrpc/streaming/session_messages.rb +119 -0
- data/lib/connectrpc/streaming/strategy.rb +95 -0
- data/lib/connectrpc/streaming/streams.rb +116 -0
- data/lib/connectrpc/streaming/terminal.rb +52 -0
- data/lib/connectrpc/transports/net_http.rb +246 -0
- data/lib/connectrpc/version.rb +5 -0
- data/lib/connectrpc.rb +38 -0
- data/rbs/google_protobuf_4_36/runtime.rbs +41 -0
- data/sig/connectrpc.rbs +772 -0
- data/sig/manifest.yaml +2 -0
- data/third_party/README.md +16 -0
- data/third_party/google/LICENSE +201 -0
- data/third_party/google/rpc/status.proto +48 -0
- data/third_party/protobuf-LICENSE +32 -0
- metadata +106 -0
data/docs/development.md
ADDED
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
Use [Mise](https://mise.jdx.dev/) >= 2026.9.14. CI pins 2026.10.19.
|
|
6
|
+
Install the [Ruby source-build prerequisites](https://github.com/rbenv/ruby-build/wiki#suggested-build-environment)
|
|
7
|
+
for your OS first; setup does not change system packages or global tool config.
|
|
8
|
+
Network access is required on first setup.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
mise run setup
|
|
12
|
+
mise exec -- ruby --version
|
|
13
|
+
mise exec -- bundle --version
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`mise.toml` pins CRuby 3.4.12 and 4.0.9, actionlint, and zizmor. Both Rubies
|
|
17
|
+
compile from upstream source. Local setup installs both, with 3.4.12 first on
|
|
18
|
+
PATH. CI uses official prebuilt runtimes instead; see
|
|
19
|
+
[CI](https://github.com/jimeh/connectrpc-ruby/blob/main/docs/ci.md). Run a
|
|
20
|
+
targeted local check on the other version with:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
MISE_RUBY_VERSION=4.0.9 mise run test
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The source-build installer is pinned to [ruby-build v20261023](https://github.com/rbenv/ruby-build/releases/tag/v20261023)
|
|
27
|
+
by commit in `ruby.ruby_build_repo`. Review its release age and commit alongside
|
|
28
|
+
Ruby updates. Compilation uses the host's compiler and system libraries, so
|
|
29
|
+
these locks do not promise bit-identical Ruby binaries across machines.
|
|
30
|
+
|
|
31
|
+
Setup installs only the declared project tools, then Bundler 4.0.23 into the
|
|
32
|
+
active Ruby, then the frozen `Gemfile.lock` into ignored `vendor/bundle/`.
|
|
33
|
+
Root Bundler user state is scoped to `vendor/bundler/`; optional bundles set
|
|
34
|
+
their own user directories.
|
|
35
|
+
Re-running setup is safe. Bundler config files are ignored so user-level
|
|
36
|
+
settings cannot silently change the bundle location or frozen behavior.
|
|
37
|
+
`mise.lock` currently locks Linux x64 downloads and checksums, including both
|
|
38
|
+
Ruby source archives. Add and review locks for other development platforms
|
|
39
|
+
with `mise lock --platform <platform>` before installing there.
|
|
40
|
+
|
|
41
|
+
## Commands and evidence
|
|
42
|
+
|
|
43
|
+
`mise tasks` is the command index. Ruby operations use Rake where useful;
|
|
44
|
+
Mise owns setup ordering and verification composition.
|
|
45
|
+
|
|
46
|
+
| Command | Purpose |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `mise run setup` | Install locked tools, pinned Bundler, frozen dependencies. |
|
|
49
|
+
| `mise run format` | Apply RuboCop Layout fixes. |
|
|
50
|
+
| `mise run format:check` | Check Layout without writing. |
|
|
51
|
+
| `mise run lint` | Run remaining RuboCop cops. |
|
|
52
|
+
| `mise run syntax` | Parse maintained library, specs, scripts, gemspec, Gemfile, Rakefile. |
|
|
53
|
+
| `mise run test -- spec/connectrpc_spec.rb` | Run focused RSpec examples; accepts `file:line` and RSpec options. |
|
|
54
|
+
| `mise run test` | Run all specs and generate coverage. |
|
|
55
|
+
| `mise run lint:workflows` | Run actionlint and offline zizmor. |
|
|
56
|
+
| `mise run check:static` | Run format, lint, and workflow checks once. |
|
|
57
|
+
| `mise run check` | Run static checks and Ruby syntax checks. |
|
|
58
|
+
| `mise run build` | Build `pkg/connectrpc-0.1.0.gem`. |
|
|
59
|
+
| `mise run check:package` | Build, install, and require the gem in isolation. |
|
|
60
|
+
| `mise run setup:generation` | Install task-local protoc 36.2 and development-only Buf 1.75.0. |
|
|
61
|
+
| `mise run generation:build` | Regenerate checked-in official messages and service glue using protoc; verify actual Buf glue parity/runtime. |
|
|
62
|
+
| `mise run generation:check` | Regenerate into temp trees, compare fixture bytes/glue parity, exercise both protoc and Buf output. |
|
|
63
|
+
| `mise run example:generated` | Compile the greeting proto and run its generated localhost client/handlers in both codecs. |
|
|
64
|
+
| `mise run example` | Run a typed ephemeral localhost Rack/NetHTTP example in both codecs. |
|
|
65
|
+
| `mise run example:server -- NAME [--mtls]` | Serve a [runnable example](../examples/README.md) server until Ctrl-C; `PORT` overrides 8080. `--mtls` (Async, Falcon) requires client certificates. |
|
|
66
|
+
| `mise run example:client -- NAME [RPC [ARGS...]]` | Call the running example server; `--list` prints servers, clients, RPCs and options. |
|
|
67
|
+
| `mise run example:verify` | Run every supported example pairing and representative refusals on ephemeral ports. |
|
|
68
|
+
| `mise run fixture:build` | Rebuild the shared descriptor fixture from its explicit Ruby schema builder. |
|
|
69
|
+
| `mise run fixture:check` | Compare the checked-in descriptor bytes to the builder. |
|
|
70
|
+
| `mise run setup:interop` | Install task-local Go 1.27.3 and download checksum-locked modules. |
|
|
71
|
+
| `mise run test:interop` | Run the Go-to-Go reference baseline and both cross-language directions/codecs, 18 original identity cases, the generated path, then 40 separate gzip cases. |
|
|
72
|
+
| `mise run setup:conformance` | Install task-local official runner 1.0.6 and protoc 36.2 with locked checksums. |
|
|
73
|
+
| `mise run conformance:build` | Generate descriptors from unchanged official schemas using protoc. |
|
|
74
|
+
| `mise run conformance:check` | Verify schema hashes and byte-for-byte descriptor regeneration. |
|
|
75
|
+
| `mise run test:conformance` | Run the declared identity and gzip client/server profiles with strict accounting; see the [conformance guide](../conformance/README.md). |
|
|
76
|
+
| `mise run verify` | Run core checks, specs, packages, generation, Go interop, official conformance, the selected Rails lane and the independent HTTP/2 and Falcon backends. |
|
|
77
|
+
|
|
78
|
+
Every entry point installs missing prerequisites through the same task graph.
|
|
79
|
+
During Ruby iteration, use focused tests and relevant static checks. Run
|
|
80
|
+
`check` for fast static feedback and `verify` for package/tooling changes and
|
|
81
|
+
final implementation handoff. Run `mise run verify` and then `mise run rack:verify`
|
|
82
|
+
for final handoff; moved middleware specs have their own canonical gate.
|
|
83
|
+
[CI](https://github.com/jimeh/connectrpc-ruby/blob/main/docs/ci.md) splits the same
|
|
84
|
+
canonical component tasks into nine core, three Rails, four optional HTTP/2,
|
|
85
|
+
two optional Rack, two optional testing, two optional RBS and four optional Falcon
|
|
86
|
+
checks, with syntax, specs, package isolation,
|
|
87
|
+
interop and official conformance on both Rubies. Hosted clean-environment and
|
|
88
|
+
matrix results remain CI evidence; a local pass cannot establish them.
|
|
89
|
+
|
|
90
|
+
Markdown is maintained manually: check relative links, commands, and fenced
|
|
91
|
+
examples when changing prose. There is no automatic Markdown formatter or
|
|
92
|
+
Node toolchain. Mise parses TOML, while actionlint and zizmor check workflows.
|
|
93
|
+
Docs-only edits do not require a test rerun unless an example changes behavior;
|
|
94
|
+
packaged-doc changes can be checked with `check:package`.
|
|
95
|
+
|
|
96
|
+
### Official conformance
|
|
97
|
+
|
|
98
|
+
[The conformance harness](../conformance/README.md) documents exact pins,
|
|
99
|
+
provenance, supported axes, lifecycle, named selectors and result artifacts.
|
|
100
|
+
`test:conformance` accepts an optional `client` or `server` direction and then
|
|
101
|
+
one exact case name from `conformance/cases.json` for troubleshooting. CI runs
|
|
102
|
+
every configured case in both directions on both pinned Rubies; `verify` runs
|
|
103
|
+
both directions on the active Ruby.
|
|
104
|
+
The 18-case independent Go identity fixture and generated baseline stay separate.
|
|
105
|
+
Focused tasks are `test:interop:identity`, `test:interop:gzip`,
|
|
106
|
+
`test:conformance:identity` and `test:conformance:gzip`. Exact conformance selectors
|
|
107
|
+
automatically choose their inventory; explicit profile tasks keep runs bounded.
|
|
108
|
+
|
|
109
|
+
Identity requires 96 actual client and 90 server passes, including two exact
|
|
110
|
+
GET names per direction. The disjoint gzip profile requires 88 client and 82
|
|
111
|
+
server passes, for 184/172 in total. There are no expected-failure manifests or
|
|
112
|
+
waivers. All four caller-cancellation cases use the original 5 ms timer armed
|
|
113
|
+
before the blocking call, the original 200 ms response request, and no deadline.
|
|
114
|
+
Their causal ledger distinguishes positively observed cancellation before
|
|
115
|
+
transport, during setup and during exchange using closed call/transport scope
|
|
116
|
+
counts, source transition and the actual library canceled/nil-cause result.
|
|
117
|
+
Missing dispatch alone cannot establish an early cancellation. A separately
|
|
118
|
+
proved `response_observed` branch allows explicit cancellation before Client's
|
|
119
|
+
terminal commit after a complete transport response, without claiming Client
|
|
120
|
+
validated/decoded it or interrupted its socket. Completed writes
|
|
121
|
+
retain actual byte/body/name/no-timeout checks; interrupted writes leave byte
|
|
122
|
+
delivery unknown. Dedicated synchronized real-wire tests prove request progress,
|
|
123
|
+
interruption/retirement and cleanup separately from the official timer scenario.
|
|
124
|
+
Lifecycle close-call telemetry leaves interruption causality unknown because
|
|
125
|
+
NetHTTP can independently close the socket; it still requires observed closure
|
|
126
|
+
and retirement for attached sockets.
|
|
127
|
+
Never gate/restart the official timer after wire progress.
|
|
128
|
+
Actual wire coding, byte counts, lengths and digests remain independently
|
|
129
|
+
checked. Ordinary reference error responses may use identity for gzip requests.
|
|
130
|
+
Timeouts, duplicate metadata and remote canceled errors must also pass normally.
|
|
131
|
+
Raw runner logs, JSON telemetry and strict JSON summaries are preserved under
|
|
132
|
+
ignored `vendor/conformance/results/`. An accounting mismatch fails even if
|
|
133
|
+
the official runner exits successfully. This evidence is distinct from full
|
|
134
|
+
conformance or unsupported configuration-space totals.
|
|
135
|
+
|
|
136
|
+
### Coverage
|
|
137
|
+
|
|
138
|
+
SimpleCov 1.3.2 starts in `spec/spec_helper.rb` before loading the library.
|
|
139
|
+
All `lib/**/*.rb` files, including unloaded files, are in scope; specs and
|
|
140
|
+
tooling are outside that scope. The test command prints line and branch
|
|
141
|
+
summaries and writes an ignored local HTML report to `coverage/index.html`.
|
|
142
|
+
Reports describe the current run, without merging prior focused runs. There is
|
|
143
|
+
no coverage threshold, upload, external service, or artifact job. A skeleton
|
|
144
|
+
with no branches may report zero total branches; its high line percentage
|
|
145
|
+
proves no protocol behavior. Coverage is regression evidence, not interoperability or production-readiness
|
|
146
|
+
proof. The separate Go peer tests establish the advertised unary subset.
|
|
147
|
+
|
|
148
|
+
### Package isolation
|
|
149
|
+
|
|
150
|
+
Canonical builders share `scripts/package_build.rb`. It loads each gem's exact
|
|
151
|
+
manifest and metadata in its owning source directory, then builds from a private
|
|
152
|
+
temporary copy with executable files set to `0755` and ordinary files to `0644`.
|
|
153
|
+
Checkout permissions and bytes remain unchanged, and each package lane builds
|
|
154
|
+
its own archives in its existing output directory. `spec/package_build_spec.rb`
|
|
155
|
+
checks real archive headers, complete file bytes, manifests and metadata under
|
|
156
|
+
umasks `002` and `022` using group-writable fixture inputs.
|
|
157
|
+
|
|
158
|
+
`check:package` asserts an explicit reviewed package manifest, zero runtime
|
|
159
|
+
dependencies, MIT metadata and complete license bytes, and the push host. It runs `gem install --norc --local`
|
|
160
|
+
from a separate temporary working directory inside `Bundler.with_unbundled_env`,
|
|
161
|
+
with fresh `GEM_HOME`/`GEM_PATH` and cleared Ruby/Bundler options. It verifies
|
|
162
|
+
core require without Google/Rack, an ordinary missing `connectrpc/rack` file
|
|
163
|
+
error, and useful missing Google/generator dependency errors.
|
|
164
|
+
It independently builds the optional Rack archive under `vendor/package/rack`,
|
|
165
|
+
stages it and only the required runtime archives in the external cwd, and uses
|
|
166
|
+
normal offline dependency resolution. It installs the cached, locked optional
|
|
167
|
+
artifacts, including native
|
|
168
|
+
`bigdecimal`, Google protobuf and its `rake` dependency, Rack, rackup and
|
|
169
|
+
WEBrick. The installed gem performs real typed Rack/NetHTTP calls with both
|
|
170
|
+
binary and JSON scalar-wrapper payloads with identity and gzip, including errors. The helper scripts are copied to the
|
|
171
|
+
external cwd; library code loads exclusively from the fresh installed gem.
|
|
172
|
+
The installed executable first proves missing Google fails helpfully with empty
|
|
173
|
+
stdout. The task retains its task-local compiler activation, and the check
|
|
174
|
+
requires `protoc --version` to report `libprotoc 36.2`. Missing executables and
|
|
175
|
+
failed commands report the command and failure status. After the optional
|
|
176
|
+
artifacts are installed, actual protoc invokes only
|
|
177
|
+
`GEM_HOME/bin/protoc-gen-connectrpc-ruby` outside the checkout with cleared
|
|
178
|
+
Ruby/Bundler source paths. The generated tree performs typed success/error,
|
|
179
|
+
metadata/trailers, nested imported types and presence calls in both codecs.
|
|
180
|
+
Google package and explicit Ruby package fixtures import ordinary WKTs, assert
|
|
181
|
+
exact official message-class identity and perform typed calls in both codecs.
|
|
182
|
+
The check does not install the development JSON gem: it exercises the Ruby
|
|
183
|
+
default JSON and Net::HTTP gems. All installs are offline and temporary files
|
|
184
|
+
are removed. Nothing is published.
|
|
185
|
+
|
|
186
|
+
Core ships no `lib/connectrpc/rack.rb`. Core `sig/`, the explicitly selected
|
|
187
|
+
`rbs/google_protobuf_4_36/` bridge, remaining `lib/**/*.rb`,
|
|
188
|
+
`exe/protoc-gen-connectrpc-ruby`, `LICENSE`, `README.md`, and the
|
|
189
|
+
design/development/[RBS guide](rbs.md) documents ship. The executable metadata and packaged execute
|
|
190
|
+
bits are checked; syntax and RuboCop include the extensionless executable.
|
|
191
|
+
The optional Rack, Rails, Async, testing and Falcon packages carry byte-identical copies of the root
|
|
192
|
+
`LICENSE`; their package checks verify both the copies and archived notices.
|
|
193
|
+
Keep these copies in sync when updating the canonical notice.
|
|
194
|
+
The exact manifest in `scripts/check_package.rb` must be deliberately updated
|
|
195
|
+
when library files are added. Specs, fixtures, examples, peer code, tooling,
|
|
196
|
+
coverage and installed development dependencies do not ship.
|
|
197
|
+
|
|
198
|
+
### Generator provenance and tools
|
|
199
|
+
|
|
200
|
+
Ordinary Specs load unique checked-in official outputs without installing
|
|
201
|
+
protoc, Buf, Go or the conformance runner. `spec/fixtures/generation/proto/`
|
|
202
|
+
owns unique schemas; `ruby/` contains protoc 36.2 message output and this
|
|
203
|
+
plugin's glue. `echo/` contains official outputs for the existing shared
|
|
204
|
+
`echo.proto`; these run in a separate process to avoid duplicate descriptor-pool
|
|
205
|
+
registration with `EchoExample`. Never hand-edit generated files.
|
|
206
|
+
|
|
207
|
+
`generation:check` regenerates messages/glue with protoc 36.2 and runs real Buf
|
|
208
|
+
1.75.0 local plugins, including the official protoc Ruby builtin. Service glue
|
|
209
|
+
must be byte-identical between compilers. Their official message descriptor bytes
|
|
210
|
+
can differ, so each output tree is independently loaded and exercised. Compiler
|
|
211
|
+
version, comments and source-code info do not affect glue. Official `_pb.rb`
|
|
212
|
+
files alone are excluded from RuboCop; glue remains checked, with scoped naming
|
|
213
|
+
and named-forwarding exceptions for the specified generated API.
|
|
214
|
+
|
|
215
|
+
Mise locks Buf's Linux x64 archive SHA256
|
|
216
|
+
`7168a06e29bd5eb8d1530848f242264f7a86b9b8af3b2e811570fbea0c929a30`,
|
|
217
|
+
verified against upstream [sha256.txt](https://github.com/bufbuild/buf/releases/download/v1.75.0/sha256.txt).
|
|
218
|
+
The stable [release API](https://api.github.com/repos/bufbuild/buf/releases/tags/v1.75.0)
|
|
219
|
+
reports publication on 2026-10-22T01:02:29Z, over seven days before the
|
|
220
|
+
2026-11-02 audit. Existing protoc and all other pins remain unchanged. Buf is
|
|
221
|
+
development-only and uses ignored `vendor/buf/cache`, never global config/cache.
|
|
222
|
+
Package CI installs both tools; Interop consumes checked-in output and needs
|
|
223
|
+
neither compiler. `example:generated` generates temporary greeting output and
|
|
224
|
+
cleans it up after observable localhost shutdown.
|
|
225
|
+
|
|
226
|
+
### Independent interoperability and fixture provenance
|
|
227
|
+
|
|
228
|
+
`test:interop` builds a reference peer with Go 1.27.3,
|
|
229
|
+
`connectrpc.com/connect` v1.21.1 and `google.golang.org/protobuf` v1.36.12.
|
|
230
|
+
Go is task-local, with its Linux x64 download checksum in `mise.lock`;
|
|
231
|
+
ordinary setup/focused Ruby checks do not need it. `GOTOOLCHAIN=local`,
|
|
232
|
+
`GOWORK=off`, `GOFLAGS=-mod=readonly` and checked-in `go.sum` prevent implicit
|
|
233
|
+
toolchain/module updates. Go's module/build caches are project-local under
|
|
234
|
+
ignored `vendor/interop/`. Setup downloads the pinned modules; tests run
|
|
235
|
+
`go mod verify` and a readonly build.
|
|
236
|
+
|
|
237
|
+
The 18 fixture cases are success, deliberate error/details/metadata, and a
|
|
238
|
+
request limit, for both codecs across Go-to-Go, Ruby-to-Go and Go-to-Ruby.
|
|
239
|
+
They use the actual connect-go Client and Handler with dynamic message
|
|
240
|
+
initialization. The Go-to-Go baseline runs while the existing Go host is alive,
|
|
241
|
+
using the same client scenarios and configured limits as Go-to-Ruby. Twelve
|
|
242
|
+
cases establish cross-language interoperability; six validate the reference
|
|
243
|
+
baseline. Success compares typed messages semantically, covering optional
|
|
244
|
+
presence, int64, enum, timestamp and bytes. The Go baseline asserts separate raw
|
|
245
|
+
request/response metadata, trailers and error metadata. Go-to-Ruby keeps exact
|
|
246
|
+
WEBrick coalescing expectations for those known fixture fields. Raw repeated Go
|
|
247
|
+
response values remain separate at NetHTTP. NetHTTP joins outgoing request
|
|
248
|
+
arrays with comma+space, and the WEBrick host also coalesces incoming and
|
|
249
|
+
response values. Assertions preserve those observed semantics without splitting
|
|
250
|
+
arbitrary comma-containing values. The separate generated process adds Ruby->Go
|
|
251
|
+
success/error calls and reuses
|
|
252
|
+
the Go client's six existing success/error/limit scenarios against generated
|
|
253
|
+
Ruby handler registration. Both codecs execute, retaining the original 18-case
|
|
254
|
+
fixture result unchanged. This is not the Connect conformance suite.
|
|
255
|
+
|
|
256
|
+
`spec/fixtures/echo.proto` documents the schema. `scripts/build_fixture.rb`
|
|
257
|
+
explicitly builds a matching `FileDescriptorProto`; it is not protoc output or
|
|
258
|
+
a protobuf parser. The checked-in `echo.bin` is the single descriptor used by
|
|
259
|
+
both peers. `fixture:check` compares it byte-for-byte with a rebuilt descriptor,
|
|
260
|
+
Ruby mapping specs exercise its types, and Go reflection checks presence,
|
|
261
|
+
int64, enum and timestamp fields. If changing the schema, update both the
|
|
262
|
+
`.proto` and builder and regenerate the bytes with `fixture:build`.
|
|
263
|
+
|
|
264
|
+
Localhost tests/examples use port 0 and bounded readiness/shutdown signals.
|
|
265
|
+
Socket lifecycle tests establish request progress, then exercise stalled body,
|
|
266
|
+
aggregate response-header trickle and blocked outbound writes. Header-trickle
|
|
267
|
+
pacing measures real elapsed network behavior, not readiness. The Ruby 3.4
|
|
268
|
+
stdlib may lazily retain its process-wide Timeout service thread; tests exclude
|
|
269
|
+
that named service from call-owned worker checks. ConnectRPC watchdogs and
|
|
270
|
+
peer/host workers must all stop, and sockets must close.
|
|
271
|
+
Pre-dispatch race tests use a controlled monotonic clock and peer-observed EOF
|
|
272
|
+
before resuming dispatch, then check for queued replacement connections after
|
|
273
|
+
the call completes. Wire timeout assertions consume budget during preparation
|
|
274
|
+
and connection. Huge finite budgets exercise real localhost I/O, with capped
|
|
275
|
+
native waits and an unchanged logical deadline. Scaled-cap socket tests verify
|
|
276
|
+
`unavailable` before logical expiry and `deadline_exceeded` after actual expiry,
|
|
277
|
+
with closure and no replacement connection. Huge-budget tests exercise native
|
|
278
|
+
conversions, not the full elapsed native-operation ceiling. Proxy configuration assertions
|
|
279
|
+
set hostile proxy environment variables and restore their previous state.
|
|
280
|
+
|
|
281
|
+
## Dependency and action updates
|
|
282
|
+
|
|
283
|
+
Keep exact direct dependency and tool pins. Check release dates against the
|
|
284
|
+
[primary RubyGems API](https://guides.rubygems.org/rubygems-org-api/) or upstream
|
|
285
|
+
GitHub releases before updating: stable releases must be at least seven days
|
|
286
|
+
old. Verify Ruby requirements for both supported Rubies. For actions, resolve
|
|
287
|
+
the upstream release tag to its commit and retain a full SHA with a tag comment.
|
|
288
|
+
Mise's minimum age filters fuzzy resolution, not explicit pins; review pinned
|
|
289
|
+
release ages manually. Bundler's source cooldown is seven days; old registries
|
|
290
|
+
or index entries lacking timestamps may not enforce it, so audit newly resolved
|
|
291
|
+
versions too. See [Bundler cooldown](https://bundler.io/man/bundle-config.1.html).
|
|
292
|
+
|
|
293
|
+
For a deliberate dependency update, edit the Gemfile, then resolve the lock
|
|
294
|
+
with frozen mode temporarily disabled. Keep the generic Ruby platform and
|
|
295
|
+
checksums, and do not add a `ruby` Gemfile directive or `RUBY VERSION` field
|
|
296
|
+
that excludes the other CI Ruby:
|
|
297
|
+
|
|
298
|
+
```sh
|
|
299
|
+
mise exec -- env BUNDLE_FROZEN=false bundle lock --update --add-platform ruby --add-checksums
|
|
300
|
+
mise lock --platform linux-x64
|
|
301
|
+
mise run setup
|
|
302
|
+
mise run verify
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Review all lock changes, including transitive dependencies. CI uses frozen
|
|
306
|
+
installation. For an urgent security fix inside the seven-day window, obtain
|
|
307
|
+
an explicit maintainer exception, record the advisory/version/reason in the PR,
|
|
308
|
+
and override cooldown only for that resolution (for example,
|
|
309
|
+
`mise exec -- env BUNDLE_COOLDOWN=0 BUNDLE_FROZEN=false bundle lock --update <gem>`).
|
|
310
|
+
Do not weaken the persistent policy. Original project work is [MIT licensed](../LICENSE).
|
|
311
|
+
The invalid push host remains an accidental-push guard, not a security boundary
|
|
312
|
+
against someone editing metadata. Publishing, releasing or deploying requires
|
|
313
|
+
separate, explicit authorization.
|
|
314
|
+
|
|
315
|
+
## Hooks and pull requests
|
|
316
|
+
|
|
317
|
+
Local hooks: deferred (`n/a`). This repository has only a tiny library and
|
|
318
|
+
canonical checks; automatic hooks add installation and partial-staging
|
|
319
|
+
semantics before there is evidence of recurring missed checks. Run `check`
|
|
320
|
+
while working and rely on CI for required verification. Reconsider a small,
|
|
321
|
+
non-writing pre-commit check if contributors repeatedly miss checks, after
|
|
322
|
+
measuring warm runtime and validating worktree/partial-staging behavior. No
|
|
323
|
+
pre-push hook is installed.
|
|
324
|
+
|
|
325
|
+
Keep PRs scoped. Describe the concrete result, relevant design boundaries,
|
|
326
|
+
commands and results (including RSpec example counts), and remaining limits.
|
|
327
|
+
Approved merges use squash merging; merge authorization remains separate.
|
|
328
|
+
Reuse valid evidence. Design changes should update [design.md](design.md).
|
|
329
|
+
Releases use a Release Please PR on main, local candidate tasks and a
|
|
330
|
+
tag-triggered publishing workflow. See the
|
|
331
|
+
[release guide](https://github.com/jimeh/connectrpc-ruby/blob/main/docs/releasing.md)
|
|
332
|
+
for App and trusted-publisher setup, synchronized versions and recovery.
|
|
333
|
+
Project MIT licensing is approved. Releasing still needs separate, explicit authorization.
|
|
334
|
+
|
|
335
|
+
## Optional Rails development
|
|
336
|
+
|
|
337
|
+
The self-contained [Rails adapter guide](../gems/connectrpc-on-rails/README.md)
|
|
338
|
+
owns controller setup, lifecycle/security limits and generated-code placement.
|
|
339
|
+
Root `Gemfile`, lock, runtime dependencies, setup and specs do not require Rails.
|
|
340
|
+
Discover adapter commands with `mise tasks`:
|
|
341
|
+
|
|
342
|
+
```sh
|
|
343
|
+
RAILS_LANE=8.0 mise run test:rails
|
|
344
|
+
RAILS_LANE=8.1 mise run verify:rails
|
|
345
|
+
MISE_RUBY_VERSION=4.0.9 RAILS_LANE=8.1 mise run verify:rails
|
|
346
|
+
mise run generation:check:rails
|
|
347
|
+
mise run build:rails
|
|
348
|
+
mise run check:package:rails
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The launcher prints Ruby, exact selected Rails, Bundler and Gemfile. Specs assert
|
|
352
|
+
actual loaded Rails/Bundler. The tested combinations are Rails 8.0.5.1/Ruby
|
|
353
|
+
3.4.12 and Rails 8.1.4/Ruby 3.4.12 or 4.0.9. The default lane is 8.1.
|
|
354
|
+
`verify` includes the selected Rails lane, not all three combinations; CI runs
|
|
355
|
+
all three independently. Adapter setup depends on `setup:bundler`, not root
|
|
356
|
+
`setup`, and uses the root ABI-specific `vendor/bundle` cache.
|
|
357
|
+
|
|
358
|
+
Actual Appraisal 2.5.0 generates the lane Gemfiles. Its parser cannot accept a
|
|
359
|
+
source cooldown keyword, so the adapter development source is plain and tasks
|
|
360
|
+
and CI enforce `BUNDLE_COOLDOWN=7`. Root source cooldown/pins/lock stay intact.
|
|
361
|
+
There is no adapter base lock: select one generated checksummed lane lock for
|
|
362
|
+
frozen installation and actual `appraisal <lane>` execution. Do not run
|
|
363
|
+
`appraisal install` in CI. The launcher checks Bundler 4.0.23 is installed
|
|
364
|
+
before Appraisal can invoke its legacy installer fallback.
|
|
365
|
+
`generation:check:rails` runs the actual generator in a temporary relative-layout
|
|
366
|
+
copy and byte-compares both outputs without touching checked-in Gemfiles.
|
|
367
|
+
Changing dependencies requires the same seven-day primary registry release-age
|
|
368
|
+
and archive checksum audit as root dependencies, including native variants.
|
|
369
|
+
|
|
370
|
+
Adapter SimpleCov includes every adapter `lib/**/*.rb` file before requires
|
|
371
|
+
and writes to `vendor/rails/coverage`, separate from core. Real app tests use
|
|
372
|
+
matching Rails defaults, native Base/API dispatch and CSRF/session behavior,
|
|
373
|
+
Rack::Lint, eager load/reload and synchronized concurrent requests.
|
|
374
|
+
`build:rails` builds core, Rack and Rails exact archives into `vendor/rails/pkg` independently
|
|
375
|
+
of root build output. `check:package:rails` checks all three manifests, guards and
|
|
376
|
+
conventional runtime dependency requirements, stages only their runtime closure, installs offline into fresh
|
|
377
|
+
GEM_HOME/GEM_PATH outside the checkout, and exercises installed generated
|
|
378
|
+
binary/JSON clients against native Rails callbacks and structured failures.
|
|
379
|
+
The adapter README, `LICENSE`, library files and its owned `sig/` manifest/signatures ship in its archive. No dependencies
|
|
380
|
+
or fixtures are vendored into either package, and nothing is published.
|
|
381
|
+
|
|
382
|
+
## Optional HTTP/2 development
|
|
383
|
+
|
|
384
|
+
The [backend guide](../gems/connectrpc-async/README.md) owns its public API,
|
|
385
|
+
reactor affinity, TLS/mTLS lifecycle, backend normalization and resource limits.
|
|
386
|
+
Use `mise run async:setup`, then focused `mise run async:test -- spec/tls_spec.rb`
|
|
387
|
+
or `async:check` while iterating. `async:build` builds its own core and backend
|
|
388
|
+
archives under `vendor/async/pkg`; `async:package` installs cached normal runtime
|
|
389
|
+
dependencies in a fresh outside-checkout GEM_HOME and performs generated
|
|
390
|
+
h2c/mTLS calls with identity and gzip plus core NetHTTP TLS/JSON in both encodings.
|
|
391
|
+
That process activates OpenSSL 4.0.2/JSON 3.1.0, so its TLS trust fixture is passed
|
|
392
|
+
only to the child process.
|
|
393
|
+
`async:example` runs the same generated localhost scenarios from development
|
|
394
|
+
sources. `async:interop` uses the existing pinned Go module graph and toolchain
|
|
395
|
+
with a separate peer executable. `async:verify` combines backend checks, product
|
|
396
|
+
specs, package isolation and independent Go interoperability; root `verify`
|
|
397
|
+
includes it alongside the existing core and selected Rails verification.
|
|
398
|
+
|
|
399
|
+
The backend Gemfile/lock is independent; do not resolve it into root or Rails
|
|
400
|
+
locks. All registry/platform artifacts require seven-day primary release-age
|
|
401
|
+
and archive checksum verification, including generic/native variants. Keep its
|
|
402
|
+
root dependency as a development-only relative path. Bundle installation and
|
|
403
|
+
native caches use `vendor/async/bundle`; Bundler user state uses
|
|
404
|
+
`vendor/async/bundler`. Only the observed generated backend `.bundle/` directory
|
|
405
|
+
is ignored. SimpleCov starts before backend/core requires, includes every
|
|
406
|
+
backend library file and writes `coverage/async/<Ruby>/`. Green coverage does
|
|
407
|
+
not establish interoperability or hosted clean-environment success.
|
|
408
|
+
|
|
409
|
+
## Optional Rack development
|
|
410
|
+
|
|
411
|
+
The [middleware guide](../gems/connectrpc-rack/README.md) owns installation,
|
|
412
|
+
mounting and lifecycle limits. Run `mise run rack:setup`, focused
|
|
413
|
+
`mise run rack:test -- spec/rack_spec.rb`, and `mise run rack:check` while iterating.
|
|
414
|
+
The frozen checksummed Gemfile reuses exact root registry pins with core as a
|
|
415
|
+
development path dependency. Bundle, Bundler user state, lint cache and build
|
|
416
|
+
outputs are isolated under `vendor/rack`; SimpleCov starts before requires and
|
|
417
|
+
covers every package source in `coverage/rack/<Ruby>/`.
|
|
418
|
+
|
|
419
|
+
`rack:build` builds its own core and middleware archives, avoiding root/Rails
|
|
420
|
+
output races. `rack:package` checks exact manifests/dependencies/guards, installs
|
|
421
|
+
core alone to prove middleware is unavailable, then resolves the Rack package
|
|
422
|
+
normally offline using staged runtime archives in an external fresh GEM_HOME.
|
|
423
|
+
It runs real Google proto/JSON identity/gzip success, errors/details and metadata
|
|
424
|
+
under Rack::Lint over ephemeral localhost NetHTTP, asserting installed core and
|
|
425
|
+
Rack source ownership. Root installed checks also retain default JSON/NetHTTP
|
|
426
|
+
and the actual installed generator. Rails checks all three local owners.
|
|
427
|
+
|
|
428
|
+
Final local handoff requires `mise run verify` followed by `mise run rack:verify`.
|
|
429
|
+
Rack verification stays separate from root `verify`. CI runs the core checks and
|
|
430
|
+
two Rack specs/check/package lanes on the existing Rubies; clean-environment
|
|
431
|
+
matrix evidence remains a hosted responsibility. No runtime savings are claimed.
|
|
432
|
+
|
|
433
|
+
See the optional [in-process testing package](../gems/connectrpc-testing/README.md) for real encoded client/server round trips without sockets.
|
|
434
|
+
|
|
435
|
+
## Optional RBS development
|
|
436
|
+
|
|
437
|
+
[The RBS guide](rbs.md) covers official message generation, opt-in service RBS,
|
|
438
|
+
strict Steep configuration, the explicit protobuf bridge and nominal alternatives.
|
|
439
|
+
`mise run rbs:setup` installs the independent frozen checksummed development
|
|
440
|
+
bundle. `rbs:check` checks protoc/Buf parity, unchanged default Ruby and official
|
|
441
|
+
message RBS, deterministic output, real generated runtime calls, RBS validation
|
|
442
|
+
and positive/negative strict consumers. It also runs the strict core
|
|
443
|
+
implementation target defined by `typecheck/source.rb`, reviewed source inventory
|
|
444
|
+
and per-package API callers.
|
|
445
|
+
Discover the focused `rbs:source`, `rbs:api`, `rbs:inventory` and capture-only
|
|
446
|
+
`rbs:proof` leaves with `mise tasks`. `rbs:package` checks every installed package
|
|
447
|
+
and composed optional environments outside the checkout, using the existing
|
|
448
|
+
scoped frozen optional setups to populate offline archives. Run both on each pinned Ruby.
|
|
449
|
+
These leaves keep their Bundler state, caches, bundle and package outputs under
|
|
450
|
+
`vendor/rbs/` and add no runtime or root-bundle dependencies.
|
|
451
|
+
|
|
452
|
+
## Optional Falcon development
|
|
453
|
+
|
|
454
|
+
The [Falcon guide](../gems/connectrpc-falcon/README.md) owns the listener,
|
|
455
|
+
worker-local TLS provider and Rack/Rails fallback contracts. Start with
|
|
456
|
+
`mise run falcon:setup`, then use focused `falcon:test` selectors and
|
|
457
|
+
`falcon:check`. `falcon:build` writes separate core/Async/Falcon archives to
|
|
458
|
+
`vendor/falcon/pkg`. `falcon:package` installs normal dependencies offline in an
|
|
459
|
+
isolated GEM_HOME and runs the actual Falcon DSL/service outside the checkout.
|
|
460
|
+
`falcon:interop` runs identity and gzip against the pinned independent Go peer,
|
|
461
|
+
including actual Falcon process workers. `falcon:verify` combines these leaves;
|
|
462
|
+
root `verify` includes it. CI runs separate Falcon specs/package and Go checks
|
|
463
|
+
across Ruby 3.4.12 and 4.0.9.
|
|
464
|
+
|
|
465
|
+
Keep its checksummed Gemfile/lock, `vendor/falcon/bundle`, Bundler user state and
|
|
466
|
+
`coverage/falcon/<Ruby>/` independent. Audit every added registry/platform
|
|
467
|
+
artifact for seven-day release age and downloaded archive SHA256. Actual worker,
|
|
468
|
+
TLS, retirement and installed-caller tests establish different properties;
|
|
469
|
+
green coverage or baseline probes do not substitute for them.
|
|
470
|
+
|
|
471
|
+
## Optional OpenTelemetry development
|
|
472
|
+
|
|
473
|
+
`mise run otel:setup` installs the independent checksummed API/SDK and integration
|
|
474
|
+
bundle under `vendor/otel`. Use `otel:test -- spec/tracing_spec.rb` for generated
|
|
475
|
+
in-process traces, `spec/native_spec.rb` for real Async/Falcon boundaries, and
|
|
476
|
+
`spec/rack_rails_spec.rb spec/rails_spec.rb` for Rack/NetHTTP and native Rails.
|
|
477
|
+
`otel:check`, `otel:build`, `otel:package`, `otel:example` and `otel:verify` are
|
|
478
|
+
discoverable leaves. Repeat `MISE_RUBY_VERSION=4.0.9 mise run otel:verify` for the
|
|
479
|
+
second pinned runtime. Coverage starts before requires and includes core and all
|
|
480
|
+
local integration libraries under `coverage/otel/<Ruby>/`. The two OTel CI leaves
|
|
481
|
+
run independently of the other package jobs. Runtime bundles never gain an SDK.
|
|
482
|
+
Package checks install normal dependencies offline into a fresh external
|
|
483
|
+
GEM_HOME, then run copied generated callers with actual SDK in-memory exports.
|
|
484
|
+
See the [package guide](../gems/connectrpc-otel/README.md) for the precise trace
|
|
485
|
+
baseline and unknown-method default-redaction limitation.
|
|
486
|
+
|
|
487
|
+
## Native streaming verification
|
|
488
|
+
|
|
489
|
+
`async:test` and `falcon:test` include the incremental shape/codec/coding/security
|
|
490
|
+
matrix, bounded output/ingress, healthy same-connection siblings and cancellation.
|
|
491
|
+
`otel:test` includes actual SDK processor-task identity, mTLS peer identity,
|
|
492
|
+
codec/handler cleanup and separate processing/HTTP completion evidence.
|
|
493
|
+
Falcon H1 focused specs distinguish the unchanged absolute 100 ms / 256 KiB
|
|
494
|
+
discard (adapter remainder and full 64 KiB read reservations) from the cooperative
|
|
495
|
+
500 ms total final-close expiry anchored at actual final HTTP flush. They check
|
|
496
|
+
EOF before hygiene, delayed callbacks spending the same budget, no reads or
|
|
497
|
+
pipeline parsing during remaining grace, admission joins before host cleanup,
|
|
498
|
+
owner interruption and real worker shutdown. Timings may overshoot under reactor
|
|
499
|
+
delay; they are not hard real-time bounds. SDK specs preserve completed delivery
|
|
500
|
+
after later hygiene/grace failure.
|
|
501
|
+
|
|
502
|
+
`async:interop:streaming` uses the unchanged pinned connect-go graph in both
|
|
503
|
+
directions for all three streaming shapes, both codecs and codings over
|
|
504
|
+
h2c/TLS/mTLS. `falcon:interop:streaming` runs the Go client against actual Falcon
|
|
505
|
+
process workers and checks worker shutdown. These supplement the original unary,
|
|
506
|
+
GET, generated, cancellation and tail-drain leaves; they do not replace them.
|
|
507
|
+
|
|
508
|
+
`async:conformance` executes native client and Async server profiles.
|
|
509
|
+
`falcon:conformance` executes only Falcon server profiles. Exact inventories are
|
|
510
|
+
290/262 identity client/server and 268/246 gzip client/server, with zero expected
|
|
511
|
+
failures. Every run checks actual runner discovery, scheduled/received names,
|
|
512
|
+
passes and closed library/transport/server lifetimes. Source transitions and
|
|
513
|
+
actual canceled library results are recorded; socket interruption remains unknown
|
|
514
|
+
without controlled wire evidence. Original unary profiles and their 5 ms before-call,
|
|
515
|
+
200 ms response-delay and nil-deadline semantics remain independent and unchanged.
|
|
516
|
+
Both native conformance and streaming Go leaves belong to each backend's verify
|
|
517
|
+
aggregate and the existing two-Ruby CI jobs. No test results are cached.
|
|
518
|
+
The Falcon-only `falcon:conformance:http1` leaf adds separate SS/CS server
|
|
519
|
+
profiles requiring 174 identity and 160 gzip passes. Root `verify` includes this
|
|
520
|
+
complete H1 gate, so use that pass for full-profile confirmation. Fresh exact
|
|
521
|
+
oversized CS selectors can be run separately for focused regression evidence;
|
|
522
|
+
do not weaken their original assertions or inventories.
|
|
523
|
+
|
|
524
|
+
`rbs:check` includes concrete generated streaming positives and exact negative
|
|
525
|
+
fixtures. `rbs:package` runs generated streaming network callers and a custom
|
|
526
|
+
streaming SPI under normal installed discovery outside the checkout, in both
|
|
527
|
+
package load orders. The [streaming guide](streaming.md) documents the fixed
|
|
528
|
+
one-second tail policy and its compatibility tradeoff.
|
|
529
|
+
|
|
530
|
+
## Official browser development
|
|
531
|
+
|
|
532
|
+
`mise run browser:setup` installs development-only tools under `vendor/browser`;
|
|
533
|
+
ordinary core setup installs no JS runtime or browser. Linux x86_64 on Ubuntu
|
|
534
|
+
24.04 is the audited platform. Python 3's standard ZIP support and tar extract
|
|
535
|
+
checksum-verified official archives without OS dependency installation. Exact
|
|
536
|
+
artifact hashes and primary publication dates live in `browser/artifacts.json`.
|
|
537
|
+
Bun 1.4.4 manages a frozen five-package lock and bundles an ESM entry to IIFE.
|
|
538
|
+
Node 24.22.1 executes Playwright 1.64.1 with Chromium 156.0.8078.4. grpc-web 2.1.1
|
|
539
|
+
and google-protobuf 4.0.3 are development-only. All pins exceed seven days.
|
|
540
|
+
|
|
541
|
+
`browser:generation:build` and `browser:generation:check` use official protoc
|
|
542
|
+
36.2, protoc-gen-grpc-web 2.1.1 and protoc-gen-js 4.0.3 binaries. Generated
|
|
543
|
+
binary/text clients, protobuf messages and canonical Any/Status remain untouched
|
|
544
|
+
by hand. `browser:test` exercises actual cross-origin generated browser clients
|
|
545
|
+
against real Async, Falcon and native Rails fixtures. `browser:verify` combines
|
|
546
|
+
generation parity and the collected browser suite. The two Browser gRPC-Web CI
|
|
547
|
+
leaves run on Ruby 3.4.12 and 4.0.9 without replacing existing checks.
|
|
548
|
+
|
|
549
|
+
Playwright explicitly uses `chromiumSandbox: false` for its owned local process
|
|
550
|
+
and `ignoreHTTPSErrors: true` for fixture TLS. No host security or trust setting
|
|
551
|
+
changes. These browser TLS calls do not establish verified authentication; the
|
|
552
|
+
SDK/mTLS focused specs separately verify peer identity on native H2 and Falcon
|
|
553
|
+
H1. No screenshots, shared browser sessions or uploads are required.
|
|
554
|
+
|
|
555
|
+
The separate `browser/reference` Go module wraps the existing official generated
|
|
556
|
+
grpc-go service with improbable-eng/grpc-web 0.15.0 for independent text browser
|
|
557
|
+
controls. Audited compress 1.20.1/cors 1.11.1 pins keep its old default graph out
|
|
558
|
+
of use; core and existing Go graphs are unchanged. The same executable uses
|
|
559
|
+
existing connect-go 1.21.1 for independent binary unary/stream wire controls.
|
|
560
|
+
Caches, executables, browser output and fixture logs stay in `vendor/browser`.
|
|
561
|
+
|
|
562
|
+
`async:conformance:web`, `falcon:conformance:web` and `rack:conformance:web` run
|
|
563
|
+
separate exact binary inventories of 138 H2 unary/SS, 276 H1/H2 unary/SS and 37
|
|
564
|
+
portable plain-H1 unary cases. Each validates actual runner names, dispatch,
|
|
565
|
+
wire arrivals, processing, observer completion and shutdown. The official runner
|
|
566
|
+
has no text axis. Existing Connect/native-gRPC inventories remain independent.
|