feat(sdks): device-id contract for usage tracking — Python/JS/Go/Elixir (MOS-14) - #349
Closed
abojja9 wants to merge 4 commits into
Closed
feat(sdks): device-id contract for usage tracking — Python/JS/Go/Elixir (MOS-14)#349abojja9 wants to merge 4 commits into
abojja9 wants to merge 4 commits into
Conversation
Source a stable, persisted, per-device id and hand it to the core so per-device billing is stable across process restarts (previously the Python SDK only had an ephemeral per-construction client_id). - New moss/client/device_id.py: file-backed ($XDG_CACHE_HOME/moss or ~/.moss /.moss-device-id) UUIDv4 sourcing, memoization, MOSS_DISABLE_TELEMETRY opt-out, ephemeral fallback on IO error. No SDK-side telemetry POST (core owns it). - Wire apply_device_id_once into MossClient.__init__ (best-effort, never raises). Verified locally: full suite 117 passed / 44 skipped against the real prebuilt inferedge-moss-core==0.8.7 wheel; 31 device-id tests pass; mypy + black clean. Native follow-up (needs CI): add set_device_id to PyIndexManager in sdks/python/bindings/src/indexmanager.rs (delegates to core IndexManager::set_device_id). Until then apply is a graceful no-op — the id is sourced+persisted but not yet handed to the core. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source a stable, persisted, per-device id and hand it to the core so per-device billing is stable across restarts. - New sdk/src/utils/deviceId.ts: file-backed (.moss-device-id under cachePath else ~/.moss) UUIDv4 sourcing, memoization, apply-once, MOSS_DISABLE_TELEMETRY opt-out, ephemeral fallback. No SDK-side telemetry POST. - Wire applyDeviceIdOnce into internalMossClient.loadIndex (best-effort; degrades to no-op when the binding lacks setDeviceId). - Add CHANGELOG [Unreleased] entry (parity with go/elixir). - bindings/src/indexmanager.rs: TODO(MOS-14) noting the napi setDeviceId method to add for parity — no functional change. Verified locally: 22 device-id unit tests pass (isolated vitest); full sdk/src typechecks clean (strict). The SDK's own npm build was NOT run — a pre-existing missing core tarball (@moss-dev/moss-core@0.8.7) blocks npm install; unrelated to this change. Native follow-up (needs CI): add the napi setDeviceId method + a core version that exposes IndexManager::set_device_id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source a stable, persisted, per-device id and pass it to the core so per-device billing is stable across restarts (Go previously sent no device id and no client id at all). - New bindings/deviceid.go: UUIDv4 sourcing, memoization, MOSS_DISABLE_TELEMETRY opt-out, ephemeral fallback. Pure Go, no cgo. Persists .moss-device-id under $XDG_CACHE_HOME/moss else <home>/.moss — the SAME scheme as the JS/Python/Elixir SDKs so one physical device resolves to a single id across languages (the MAD metric this fixes). - bindings/libmoss.go: route both client constructors through moss_client_new_with_device_id when enabled, else moss_client_new (opt-out). - Standardization: add BSD-2-Clause LICENSE (from the swift SDK) + CHANGELOG. Verified locally: gofmt clean, go vet clean, go test ./bindings passes (6 tests, default tags — exercises deviceid.go incl. the path scheme). Native follow-up (needs CI): the cgo path (-tags libmoss) needs the vendored libmoss.h regenerated to declare moss_client_new_with_device_id. go build -tags libmoss will fail until then — documented above the cgo import. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source a stable, persisted, per-device id and share it across all telemetry surfaces (ManageClient, IndexManager, Session) so per-device billing is stable across restarts. - New lib/moss/device_id.ex: UUIDv4 sourcing under $XDG_CACHE_HOME/moss else <home>/.moss (.moss-device-id) — same scheme as JS/Python/Go so one device resolves to a single id; memoization, apply-once, MOSS_DISABLE_TELEMETRY opt-out, ephemeral fallback. No SDK-side telemetry POST. - Thread the id through Moss.Client.new/3 into all three surfaces. - ExUnit tests mirroring the reference. Verified locally (elixir 1.20.2 / OTP 29): device_id.ex compiles and all 20 tests pass (no doctest) in an isolated mix project; the 4 wiring modules parse clean. The full SDK app can't compile here — its moss_core NIF dep needs a prebuilt core not vendored in this repo (CI only). Native follow-up (needs CI): add manager/session/manage_set_device_id NIFs (delegating to core set_device_id); until then apply is a graceful no-op. TODOs in each surface name the exact change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Closing — wrong repo. MOS-14 is scoped to |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Brings the device-id "better tracking" contract to the Python, JS, Go, and Elixir SDKs, using Swift + the internal TS SDK as the reference. This is the SDK-layer half of MOS-14 (SDK parity).
"Better tracking" = each SDK sources a stable, persisted, per-device id and hands it to the core. The closed core already owns the
/telemetryPOST/buffer/flush — no SDK adds telemetry transport; the id is the per-device billing (MAD) key. Today these four SDKs (unlike Swift) sent only an ephemeral per-construction id (Go sent nothing), so a process restart looked like a new device.Contract (identical across all four)
.moss-device-idundercachePath(where the SDK has one) else$XDG_CACHE_HOME/moss/<home>/.moss— non-synced, non-migrating, and the same scheme in every language so one physical device resolves to a single id.MOSS_DISABLE_TELEMETRY(checked before the memo fast-path).loadIndex/query./telemetrycode in any SDK.Verified locally
tsccleangofmt/go vetclean;go test6 passEach binding must expose the setter and be built against a core that has
IndexManager::set_device_id(present in the internal core). Until then the apply is a graceful no-op — the id is sourced+persisted but not yet handed to the core. TODOs mark each site:set_device_idon pyo3PyIndexManagersetDeviceId(TODO(MOS-14)inbindings/src/indexmanager.rs)libmoss.hto declaremoss_client_new_with_device_id(cgo)manager/session/manage_set_device_idNIFsSub-issue mapping
Python → MOS-21 · JS → MOS-22 · Elixir → MOS-23 · Go has no sub-issue yet (recommend filing one). Also adds Go
LICENSE+CHANGELOG(were missing).🤖 Generated with Claude Code