twilic 3.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 77255a004384acecbf760c61ac408ed7b68e2c7fc024fe531eaa12d22a98871f
4
+ data.tar.gz: '06395f1bc4a676a50b35d7579a9840f27ce344b7dd67ac5043dcb3864dd989de'
5
+ SHA512:
6
+ metadata.gz: 8a7c06ce15e75fbeb76a8b0c71fd7d652accb1a2e1fe2033eb4bcae7c458be638918850daad0780a8cce27d6ee6ef20de2e74736923b190c25b9a8df1558acbb
7
+ data.tar.gz: 83f906d9fd124badec3bcb963aa0c9e9279012dd46dfd435872b63d29518e5c5598cc8ea2c39b22fc0ce2ac53f3bc0b37ecaac9acfe52d2333ee3782f3b60212
data/.editorconfig ADDED
@@ -0,0 +1,18 @@
1
+ root = true
2
+
3
+ [*.{rb,rake,yml,yaml,md,sh}]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+
9
+ [*.{rb,rake}]
10
+ indent_style = space
11
+ indent_size = 2
12
+
13
+ [*.{yml,yaml,md,sh}]
14
+ indent_style = space
15
+ indent_size = 2
16
+
17
+ [*.md]
18
+ trim_trailing_whitespace = false
data/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ * text=auto eol=lf
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /node_modules/
2
+ /.bundle/
3
+ /vendor/bundle/
4
+ /pkg/
5
+ /coverage/
6
+ *.gem
7
+ .DS_Store
8
+ /scripts/rust-client-check/target/
9
+ /scripts/rust-server-fixtures/target/
@@ -0,0 +1,22 @@
1
+ {
2
+ "default": true,
3
+ "MD013": false,
4
+ "MD004": {
5
+ "style": "dash"
6
+ },
7
+ "MD007": {
8
+ "indent": 2
9
+ },
10
+ "MD029": {
11
+ "style": "ordered"
12
+ },
13
+ "MD031": true,
14
+ "MD032": true,
15
+ "MD040": true,
16
+ "MD046": {
17
+ "style": "fenced"
18
+ },
19
+ "MD024": {
20
+ "siblings_only": true
21
+ }
22
+ }
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ twilic (3.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.3)
10
+ json (2.19.5)
11
+ language_server-protocol (3.17.0.5)
12
+ lint_roller (1.1.0)
13
+ minitest (5.27.0)
14
+ parallel (2.1.0)
15
+ parser (3.3.11.1)
16
+ ast (~> 2.4.1)
17
+ racc
18
+ prism (1.9.0)
19
+ racc (1.8.1)
20
+ rainbow (3.1.1)
21
+ rake (13.4.2)
22
+ regexp_parser (2.12.0)
23
+ rubocop (1.86.2)
24
+ json (~> 2.3)
25
+ language_server-protocol (~> 3.17.0.2)
26
+ lint_roller (~> 1.1.0)
27
+ parallel (>= 1.10)
28
+ parser (>= 3.3.0.2)
29
+ rainbow (>= 2.2.2, < 4.0)
30
+ regexp_parser (>= 2.9.3, < 3.0)
31
+ rubocop-ast (>= 1.49.0, < 2.0)
32
+ ruby-progressbar (~> 1.7)
33
+ unicode-display_width (>= 2.4.0, < 4.0)
34
+ rubocop-ast (1.49.1)
35
+ parser (>= 3.3.7.2)
36
+ prism (~> 1.7)
37
+ ruby-progressbar (1.13.0)
38
+ unicode-display_width (3.2.0)
39
+ unicode-emoji (~> 4.1)
40
+ unicode-emoji (4.2.0)
41
+
42
+ PLATFORMS
43
+ arm64-darwin-24
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ minitest (~> 5.25)
48
+ rake (~> 13.2)
49
+ rubocop (~> 1.69)
50
+ twilic!
51
+
52
+ BUNDLED WITH
53
+ 2.5.23
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Twilic (maintained by Minagishl)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # Twilic (Ruby)
2
+
3
+ Ruby implementation of the Twilic wire format and session-aware encoder/decoder.
4
+
5
+ This gem's default `Twilic.encode` / `Twilic.decode` API targets Twilic v2.
6
+
7
+ ## What this gem provides
8
+
9
+ - Dynamic encoding/decoding (`Twilic.encode`, `Twilic.decode`)
10
+ - Schema-aware encoding (`Twilic.encode_with_schema`)
11
+ - Batch and micro-batch encoding (`Twilic.encode_batch`, `SessionEncoder#encode_micro_batch`)
12
+ - Stateful features (base snapshots, state patch, template batch, control stream, trained dictionary)
13
+
14
+ ## Project layout
15
+
16
+ ```text
17
+ twilic-ruby/
18
+ lib/twilic.rb # public API
19
+ lib/twilic/core/ # wire, model, codec, session, protocol, v2
20
+ scripts/ # Rust interop fixtures and smoke checks
21
+ docs/
22
+ ```
23
+
24
+ The repository root stays thin: `require "twilic"` only. Implementation details live under `lib/twilic/core/`, similar to `internal/core/` in the Go module.
25
+
26
+ ## Requirements
27
+
28
+ - Ruby 3.3 or later
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ gem install twilic
34
+ ```
35
+
36
+ Or add to your Gemfile:
37
+
38
+ ```ruby
39
+ gem "twilic"
40
+ ```
41
+
42
+ ## Quick start
43
+
44
+ ```ruby
45
+ require "twilic"
46
+
47
+ value = Twilic.map(
48
+ "id" => Twilic.u64(1001),
49
+ "name" => Twilic.string("alice")
50
+ )
51
+
52
+ bytes = Twilic.encode(value)
53
+ decoded = Twilic.decode(bytes)
54
+ puts Twilic.equal(decoded, value) # => true
55
+ ```
56
+
57
+ ## Session encoder example
58
+
59
+ ```ruby
60
+ require "twilic"
61
+
62
+ enc = Twilic.new_session_encoder
63
+
64
+ value = Twilic.map(
65
+ "id" => Twilic.u64(1),
66
+ "role" => Twilic.string("admin")
67
+ )
68
+
69
+ bytes = enc.encode(value)
70
+ ```
71
+
72
+ ## Development
73
+
74
+ Run checks locally:
75
+
76
+ ```bash
77
+ bundle install
78
+ bundle exec rake test
79
+ ```
80
+
81
+ Rust client interop smoke check (Ruby server -> Rust client):
82
+
83
+ ```bash
84
+ bash scripts/check-rust-client-interop.sh
85
+ ```
86
+
87
+ Ruby client interop smoke check (Rust server -> Ruby client):
88
+
89
+ ```bash
90
+ bash scripts/check-ruby-client-interop.sh
91
+ ```
92
+
93
+ Run both directions:
94
+
95
+ ```bash
96
+ bash scripts/check-interop.sh
97
+ ```
98
+
99
+ Note: these scripts expect `../twilic-rust` to exist as a sibling directory.
100
+
101
+ ## Markdown formatting
102
+
103
+ Documentation is formatted and linted with Prettier and markdownlint (see [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md)).
104
+
105
+ ## CI and release (GitHub Actions)
106
+
107
+ - CI workflow: `.github/workflows/ci.yml`
108
+ - Interop workflow: `.github/workflows/interop.yml`
109
+ - Release workflow: `.github/workflows/publish-gem.yml` (tag `v*` must match `lib/twilic/version.rb`)
110
+
111
+ ## Spec parity
112
+
113
+ This gem mirrors the Twilic wire format spec at [twilic/twilic](https://github.com/twilic/twilic) and stays in lockstep with the [Rust](https://github.com/twilic/twilic-rust), [Go](https://github.com/twilic/twilic-go), and [Zig](https://github.com/twilic/twilic-zig) reference implementations.
114
+
115
+ See [`docs/SPEC-TEST-TRACEABILITY.md`](docs/SPEC-TEST-TRACEABILITY.md) for the spec-section to test mapping.
116
+
117
+ ## License
118
+
119
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task default: :test
data/docs/CHANGELOG.md ADDED
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [3.0.0] - 2026-05-24
10
+
11
+ Initial public release of the Ruby implementation of Twilic, tracking the v3 release line shared with [twilic-rust](https://github.com/twilic/twilic-rust) and [twilic-js](https://github.com/twilic/twilic-js).
12
+
13
+ ### Added
14
+
15
+ - Core wire format with dynamic `Value` model and `Encode` / `Decode` APIs.
16
+ - Schema-aware encoding (`encode_with_schema`), batch encoding (`encode_batch`), and session-based micro-batch and patch support.
17
+ - Stateful transport features: base snapshots, state patch encoding, template batch handling, control stream support, and trained dictionary support.
18
+ - Public gem API at `Twilic` with implementation under `lib/twilic/core/`.
19
+ - Spec conformance tests and traceability mapping in [`docs/SPEC-TEST-TRACEABILITY.md`](SPEC-TEST-TRACEABILITY.md).
20
+ - Rust interop fixture stream, value parity tests, and bidirectional smoke scripts under `scripts/`.
21
+ - Interop helpers in `lib/twilic/core/interop_fixtures.rb` for cross-language fixture emission and decoding.
22
+ - GitHub Actions workflows for CI, Interop, commitlint, invisible character check, PR message validation, and tagged gem publish via RubyGems Trusted Publishing (OIDC).
23
+ - GitHub issue templates, pull request template, and contributor documentation.
24
+ - Markdown formatting with Prettier and markdownlint.
25
+
26
+ ### Fixed
27
+
28
+ - PR Message Check: skip template validation for Dependabot pull requests.
29
+
30
+ [unreleased]: https://github.com/twilic/twilic-ruby/compare/v3.0.0...HEAD
31
+ [3.0.0]: https://github.com/twilic/twilic-ruby/releases/tag/v3.0.0
@@ -0,0 +1,51 @@
1
+ # Contributing
2
+
3
+ Thank you for improving the Twilic Ruby implementation.
4
+
5
+ ## Scope
6
+
7
+ This gem implements the Twilic wire format and session-aware encoder/decoder. Keep changes aligned with the normative spec in [twilic/twilic](https://github.com/twilic/twilic).
8
+
9
+ ## Development
10
+
11
+ Requirements:
12
+
13
+ - Ruby 3.3 or later
14
+ - Bundler
15
+
16
+ Implementation code belongs in `lib/twilic/core/`. The repository root (`lib/twilic.rb`) re-exports the stable public API.
17
+
18
+ ```bash
19
+ bundle install
20
+ bundle exec rake test
21
+ ```
22
+
23
+ Markdown in this repository is formatted with Prettier and linted with markdownlint (same tooling as [twilic/twilic](https://github.com/twilic/twilic)):
24
+
25
+ ```bash
26
+ pnpm install
27
+ pnpm format # write
28
+ pnpm format:check # CI check
29
+ pnpm lint # markdownlint
30
+ ```
31
+
32
+ Interop scripts under `scripts/` expect `../twilic-rust` as a sibling clone. They verify Rust and Ruby decode the same logical values and that `bundle exec rake test TEST=test/twilic/core/interop_fixtures_test.rb` passes (encode/decode roundtrip, wire parity, and cross-language value checks).
33
+
34
+ ## Commit Messages
35
+
36
+ We follow [Conventional Commits](https://www.conventionalcommits.org/).
37
+
38
+ Examples:
39
+
40
+ - `feat: add FOR bitpack vector codec`
41
+ - `fix(session): reset intern table on control frame`
42
+
43
+ ## Contribution Checklist
44
+
45
+ - Tests added or updated for behavior changes
46
+ - `bundle exec rake test` passes locally
47
+ - `pnpm format:check` and `pnpm lint` pass when Markdown changes
48
+ - Interop fixtures updated when wire behavior changes
49
+ - Commit messages follow Conventional Commits
50
+
51
+ By contributing to this repository, you agree that your contribution may be distributed under the MIT license used by the project.
@@ -0,0 +1,87 @@
1
+ # SPEC Test Traceability (5/6/8/10/13/15/18)
2
+
3
+ This file maps `twilic/SPEC.md` requirements to Ruby tests in `twilic-ruby`.
4
+
5
+ ## 5. Dynamic Profile
6
+
7
+ | SPEC section | Requirement (short) | Tests |
8
+ | --------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
9
+ | 5.2 key table | First key literal, later key ref by id | `DynamicProfileSpecTest#test_two_field_map_keeps_map_and_uses_key_ids` |
10
+ | 5.3 shape table | Repeated shape registration/promotion behavior | `DynamicProfileSpecTest#test_shape_promotes_after_second_three_field_map` |
11
+ | 5.4 MAP | Map roundtrip and key-ref decode behavior | `DynamicProfileSpecTest#test_two_field_map_keeps_map_and_uses_key_ids`, `TwilicTest#test_codec_roundtrip_dynamic_value` |
12
+ | 5.5 ARRAY | ARRAY vs typed vector threshold behavior | `DynamicProfileSpecTest#test_typed_vector_threshold_is_applied` |
13
+
14
+ ## 6. Bound Profile
15
+
16
+ | SPEC section | Requirement (short) | Tests |
17
+ | ----------------- | --------------------------------------- | ----------------- |
18
+ | 6.1 schema | Required field handling, schema decode | _not yet covered_ |
19
+ | 6.2 schema_id | Emit on first use, omit in same context | _not yet covered_ |
20
+ | 6.3 SCHEMA_OBJECT | Schema object message roundtrip | _not yet covered_ |
21
+
22
+ ## 8. Numeric Encoding
23
+
24
+ | SPEC section | Requirement (short) | Tests |
25
+ | --------------------------- | ------------------------------------------------------------------------- | ----------------- |
26
+ | 8.1 scalar integer | Zigzag/varuint scalar integer behavior | _not yet covered_ |
27
+ | 8.2 range-aware bit packing | Bounded integer handling in schema context with fixed-width range offsets | _not yet covered_ |
28
+ | 8.4 vector integer codecs | Plain/direct/delta/FOR/delta-FOR/delta-delta/RLE/patched/Simple8b | _not yet covered_ |
29
+ | 8.5 float vector codecs | XOR float vs plain behavior | _not yet covered_ |
30
+
31
+ ## 10. Strings
32
+
33
+ | SPEC section | Requirement (short) | Tests |
34
+ | --------------------------- | --------------------------------------------------- | ----------------- |
35
+ | 10.2 LITERAL | Literal mode encode/decode | _not yet covered_ |
36
+ | 10.3 REF | String ref reuse behavior | _not yet covered_ |
37
+ | 10.4 PREFIX_DELTA | Prefix-delta mode encode/decode | _not yet covered_ |
38
+ | 10.5 string table | Reset clears string table state | _not yet covered_ |
39
+ | 10.6 field-local dictionary | String dictionary/ref behavior in column codec path | _not yet covered_ |
40
+ | 10.8 INLINE_ENUM | Control-driven enum promotion path | _not yet covered_ |
41
+
42
+ ## 13. Batch / Stateful Extensions
43
+
44
+ | SPEC section | Requirement (short) | Tests |
45
+ | ----------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
46
+ | 13.1 ROW_BATCH | Small batch uses row batch | _not yet covered_ |
47
+ | 13.2 COLUMN_BATCH | Large batch uses column batch and null strategy paths | _not yet covered_ |
48
+ | 13.5.1 session state | Unknown reference policy behavior (base/template/dict families) | `TwilicTest#test_unknown_reference_policy_supports_stateless_retry` |
49
+ | 13.5.2 BASE_SNAPSHOT | Snapshot registration/reference | `InteropFixturesTest#test_codec_encode_decode_roundtrip` |
50
+ | 13.5.3 STATE_PATCH | Patch roundtrip and bounds checks | `TwilicTest#test_session_patch_and_micro_batch`, `InteropFixturesTest#test_session_encode_decode_roundtrip` |
51
+ | 13.5.4 previous-message patch | Previous-message patch selection | _not yet covered_ |
52
+ | 13.5.5 TEMPLATE_BATCH | Template create/reuse and changed mask | `TwilicTest#test_session_patch_and_micro_batch`, `InteropFixturesTest#test_session_encode_decode_roundtrip` |
53
+ | 13.5.6 CONTROL_STREAM | Plain/RLE/Bitpack/Huffman/Fse paths and compaction behavior | `InteropFixturesTest#test_decode_rust_server_frames` |
54
+ | 13.5.7 trained dictionary | Dictionary id assignment and `dict_id + compressed block` path in column encoding | _not yet covered_ |
55
+ | 13.5.8 RESET_STATE | Reset clears tables/state references | _not yet covered_ |
56
+
57
+ ## 18. Encoder Auto-Selection Rules
58
+
59
+ | Rule cluster | Requirement (short) | Tests |
60
+ | ------------------------ | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
61
+ | Dynamic map/shape rules | Repeated-shape promotion, map fallback, key refs | `DynamicProfileSpecTest#test_shape_promotes_after_second_three_field_map`, `DynamicProfileSpecTest#test_two_field_map_keeps_map_and_uses_key_ids` |
62
+ | Typed vector rules | Array cardinality/type based vectorization | `DynamicProfileSpecTest#test_typed_vector_threshold_is_applied` |
63
+ | String mode rules | Empty/literal/ref/prefix-delta transitions | _not yet covered_ |
64
+ | Batch selection rules | Row vs column threshold, micro-batch shape requirement | _not yet covered_ |
65
+ | Stateful patch threshold | Prefer patch only at low change ratio | _not yet covered_ |
66
+ | Numeric codec choice | i64/u64/float codec heuristics | _not yet covered_ |
67
+
68
+ ## 15. Trained Dictionary Transport
69
+
70
+ | SPEC section | Requirement (short) | Tests |
71
+ | --------------------------------- | ------------------------------------------------------------------------------------------------------ | ----------------- |
72
+ | 15.4 trained dictionary transport | Dictionary transport carries id/version/hash/invalidation/fallback metadata and validates payload hash | _not yet covered_ |
73
+
74
+ ## Interop Coverage
75
+
76
+ | Area | Tests |
77
+ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
78
+ | Ruby fixture encode/decode roundtrip | `InteropFixturesTest#test_codec_encode_decode_roundtrip`, `InteropFixturesTest#test_session_encode_decode_roundtrip` |
79
+ | Rust server -> Ruby client | `InteropFixturesTest#test_decode_rust_server_frames`, `scripts/check-ruby-client-interop.sh` |
80
+ | Ruby server -> Rust client | `InteropFixturesTest#test_rust_decodes_ruby_frames_with_same_values`, `scripts/check-rust-client-interop.sh` |
81
+
82
+ ## Current Gaps (explicit)
83
+
84
+ - Most bound-profile, numeric codec, string mode, batch selection, and trained-dictionary spec sections are not yet covered by dedicated Ruby tests.
85
+ - Optional-only extension note: Section 6.4 (zero-copy layout) is not implemented as a conformance target.
86
+ - Optional-only extension note: Section 10.7 (static dictionary) is not implemented as a conformance target.
87
+ - Rust-dependent interop tests skip when `twilic-rust` is not checked out (expected `../twilic-rust` sibling or `TWILIC_RUST_ROOT`).
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "twilic/core/v2"
4
+ require "twilic/core/protocol"
5
+
6
+ module Twilic
7
+ module Core
8
+ module API
9
+ module_function
10
+
11
+ def encode(value)
12
+ V2.encode_v2(value)
13
+ end
14
+
15
+ def decode(bytes)
16
+ V2.decode_v2(bytes)
17
+ end
18
+
19
+ def encode_with_schema(schema, value)
20
+ enc = Protocol::SessionEncoder.new(Session::SessionOptions.default)
21
+ enc.encode_with_schema(schema, value)
22
+ end
23
+
24
+ def encode_batch(values)
25
+ enc = Protocol::SessionEncoder.new(Session::SessionOptions.default)
26
+ enc.encode_batch(values)
27
+ end
28
+ end
29
+ end
30
+ end