billdogeng 1.0.2.pre.beta.3

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: dfff3e8914b52fef194e6ba43a996ca3a9fbf9aa3c35bcb0a842e9df8013f997
4
+ data.tar.gz: fe59c1944e99b1fb80344d75780f5d73024c209d15e051eb10c264576ac9133b
5
+ SHA512:
6
+ metadata.gz: 28df3557077d20a6638ca9bc51d5a8984e33ff413b987fed508f7d5a1f8fdaa8466e5d3f5dc4c2589d7930a4a23af6eb69fb1a92f9995a679631d6ca2d2d08bf
7
+ data.tar.gz: 4b7c2897e20fa020d6c40f58fc651c80e5378c8707d503aa6cf1f1d6eefd4cf88fe0bd16a0ff72a17e6e80e797d3556491013a7c66d1774212f42b052ded2681
data/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # billdogeng (Ruby)
2
+
3
+ Official **BilldogEng** server SDK for Ruby — the engagement suite for
4
+ server-side use: **Analytics**, **Feature Flags** (remote + local evaluation),
5
+ **Surveys** (data API), **Messaging** dispatch, and **LLM** observability.
6
+
7
+ Pure Ruby standard library (`net/http`, `json`, `zlib`) — no runtime
8
+ dependencies. Wire-compatible with every other `billdogeng-*` server SDK so the
9
+ cross-language parity corpus passes.
10
+
11
+ ## Install
12
+
13
+ ```ruby
14
+ # Gemfile
15
+ gem "billdogeng"
16
+ ```
17
+
18
+ ```sh
19
+ bundle install
20
+ # or
21
+ gem install billdogeng
22
+ ```
23
+
24
+ ## Quickstart
25
+
26
+ ```ruby
27
+ require "billdogeng"
28
+
29
+ bd = BilldogEng.new("bd_test_xxx", local_evaluation: true)
30
+
31
+ # Analytics (batched + background flush + gzip + backoff retry)
32
+ bd.capture("user-123", "order_completed", { "revenue" => 49.99 })
33
+ bd.identify("user-123", { "email" => "a@b.com", "plan" => "pro" })
34
+ bd.group_identify("company", "acme", { "seats" => 50 })
35
+ bd.alias("user-123", "anon-abc")
36
+
37
+ # Feature flags (local, deterministic murmurhash3 bucketing)
38
+ on = bd.feature_enabled?("new_checkout", "user-123")
39
+ value = bd.get_feature_flag("new_checkout", "user-123",
40
+ person_properties: { "plan" => "pro" })
41
+ payload = bd.get_feature_flag_payload("new_checkout", "user-123")
42
+ all = bd.get_all_flags("user-123")
43
+
44
+ # Surveys (data API)
45
+ list = bd.surveys.list("user-123")
46
+ config = bd.surveys.fetch(survey_id, "user-123")
47
+ start = bd.surveys.start(survey_id, customer_id: "user-123", idempotency_key: "idem-1")
48
+ bd.surveys.record_partial(survey_id, start["respondent_id"], answers)
49
+ bd.surveys.submit(survey_id, answers, respondent_id: start["respondent_id"])
50
+ bd.surveys.abandon(survey_id, start["respondent_id"])
51
+
52
+ # Messaging dispatch (Bearer JWT, not X-BillDog-API-Key)
53
+ bd.messaging.dispatch(
54
+ project_id: "…",
55
+ channel: "push",
56
+ content: { "title" => "Hi", "body" => "There" },
57
+ targeting: { "type" => "all" },
58
+ scheduling: { "deliveryType" => "immediate" },
59
+ access_token: "<supabase-session-jwt>",
60
+ )
61
+
62
+ # LLM observability
63
+ bd.llm.capture_trace(
64
+ trace_id: "t-1", span_id: "s-1", model: "claude-opus-4-8",
65
+ input_text: "hello", output_text: "hi",
66
+ prompt_tokens: 10, completion_tokens: 5, duration_ms: 123, cost_usd: 0.002,
67
+ )
68
+
69
+ # Flush remaining events and stop the background timer.
70
+ bd.shutdown
71
+ ```
72
+
73
+ ## Configuration
74
+
75
+ | Option | Default | Description |
76
+ | ------------------- | ------------------------------ | -------------------------------------------- |
77
+ | `host` | `https://api.billdog.io/v1` | Base URL for all requests |
78
+ | `flush_at` | `20` | Queue size that triggers an automatic flush |
79
+ | `flush_interval` | `10_000` | Background flush cadence (ms) |
80
+ | `max_queue_size` | `1000` | Drop oldest events beyond this |
81
+ | `gzip` | `true` | Gzip large request bodies |
82
+ | `local_evaluation` | `false` | Evaluate feature flags locally (server only) |
83
+ | `request_timeout` | `10_000` | Per-request timeout (ms) |
84
+ | `max_retries` | `3` | Retry attempts for 5xx / 429 / network |
85
+ | `enable_logging` | `false` | Verbose diagnostics to stderr |
86
+
87
+ Auth: every request sends `X-BillDog-API-Key: <apiKey>` (`bd_test_*` sandbox /
88
+ `bd_live_*` live). Messaging dispatch instead authenticates with a per-call
89
+ Bearer JWT (`access_token`).
90
+
91
+ ## Exhausted allowance (`quota_limited`)
92
+
93
+ Ingestion answers a drained meter with **HTTP 200** and a top-level
94
+ `quota_limited` array — never an error status — so your app is never broken by
95
+ your BillDog meter filling up. The data in that batch was **not** stored.
96
+
97
+ The SDK reads those 200s and suspends: it stops flushing, `capture` /
98
+ `identify` / `group_identify` / `alias` become no-ops (buffering data the server
99
+ has already refused would just grow your process's memory), and the reason is
100
+ written to stderr **once**, regardless of `enable_logging` — it is the only
101
+ signal your pipeline has gone dark:
102
+
103
+ ```
104
+ [BilldogEng:analytics] Your free plan's monthly events allowance (1,000,000) is exhausted — this data was not stored.
105
+ ```
106
+
107
+ It also heals itself: every 15 minutes one probe batch is allowed through, and
108
+ the first one accepted resumes normal flushing (logging `allowance restored`
109
+ once). So a monthly reset or a plan upgrade brings the pipeline back with no
110
+ redeploy. `flush` / `shutdown` never raise or block on a quota refusal.
111
+
112
+ ## Feature-flag evaluation
113
+
114
+ Local evaluation fetches flag **definitions** from `/feature-flag-definitions`
115
+ once, caches them (5-minute TTL / `reload_feature_flag_definitions`), and
116
+ evaluates deterministically:
117
+
118
+ 1. missing / inactive → `false`
119
+ 2. the flag's `targeting_rule` — the ONE canonical audience DSL, evaluated by
120
+ `BilldogEng::Targeting` — must match, else `false`. AND/OR combinators, date
121
+ windows, rule status, group membership, experiment-variant dependencies and
122
+ the full operator set all resolve locally, with no server round-trip:
123
+
124
+ ```ruby
125
+ bd.get_feature_flag("beta", "user-123",
126
+ country: "US", platform: "ios",
127
+ app_version: "2.5", sdk_version: "1.4",
128
+ groups: { "organisation" => "acme" },
129
+ person_properties: { "plan" => "pro" },
130
+ experiment_variants: { "exp-1" => "treatment" })
131
+ ```
132
+
133
+ `country` / `platform` / `app_version` / `sdk_version` each fall back to a
134
+ same-named person property when not passed explicitly.
135
+ 3. `bucket = murmurhash3("flag:{key}:{distinct_id}") % 100`; ON iff `bucket < rollout_percentage`
136
+ 4. multivariate: walk `variants` by cumulative rollout against an INDEPENDENT
137
+ hash, `murmurhash3("flag-variant:{key}:{distinct_id}") % 100`
138
+
139
+ Conditions that only the database can answer (`segment`, `cohort`,
140
+ `survey_answer`, `event_fired_in_window`, `group_property`) are never guessed at:
141
+ they go **cold** and the flag is resolved against the server instead. Such flags
142
+ are normally already marked `requires_server_evaluation`.
143
+
144
+ The `murmurhash3` (32-bit, seed 0, UTF-8 bytes) is identical across web / iOS /
145
+ Android / every server SDK, so a user buckets the same everywhere. Both the
146
+ bucketing and the audience evaluator are pinned to fixtures generated from the
147
+ backend (`tests/fixtures/flag-bucketing.json`, `tests/fixtures/flag-targeting.json`).
148
+
149
+ ## Tests
150
+
151
+ ```sh
152
+ bundle install && bundle exec rspec
153
+ ```
154
+
155
+ Covers: batching (10 captures → 1 POST), identify/group shapes, the 12 canonical
156
+ murmurhash3 vectors + rollout/targeting/multivariate eval, 503-then-200 retry
157
+ with backoff, the `quota_limited` 200 suspend / self-heal path, and a survey
158
+ round-trip + messaging dispatch shape (all against a local WEBrick stub).
159
+
160
+ ## BillDog Auth
161
+
162
+ Session-token verification is **not available in this SDK yet**.
163
+ [`billdogeng-node`](https://www.npmjs.com/package/billdogeng-node) is the only
164
+ server SDK that can verify a BillDog Auth token offline today.
165
+
166
+ Until it lands here, either verify in a Node service, or call the
167
+ `auth-introspect` endpoint over HTTP — that costs a network round-trip per
168
+ check, and in exchange tells you whether the session is live *right now* rather
169
+ than only that the token was valid when it was issued.
170
+
171
+ ## License
172
+
173
+ MIT