wardx 0.1.3 → 0.1.4
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.
- package/README.md +39 -4
- package/package.json +9 -4
- package/src/index.d.ts +88 -0
package/README.md
CHANGED
|
@@ -6,6 +6,41 @@ The SDK records logs, events, and metrics. The SDK also gets Remote Config and a
|
|
|
6
6
|
|
|
7
7
|
A measure call changes local memory only. The SDK sends frames on a timer. The SDK uses HTTP `POST /v1/sync` with JSON and gzip.
|
|
8
8
|
|
|
9
|
+
```text
|
|
10
|
+
AGENT
|
|
11
|
+
arisa.sh / Codex / Claude
|
|
12
|
+
│
|
|
13
|
+
MCP stdio
|
|
14
|
+
tools + wardx://project/{name}
|
|
15
|
+
▼
|
|
16
|
+
┌───────────────────────────────────────────────────┐
|
|
17
|
+
│ wardx-server (one process) │
|
|
18
|
+
│ N isolated projects │
|
|
19
|
+
│ │
|
|
20
|
+
│ MCP ──► ControlService │
|
|
21
|
+
│ ├── Remote Config snapshot │
|
|
22
|
+
│ ├── Experiment definitions │
|
|
23
|
+
│ ├── Aggregates │
|
|
24
|
+
│ ├── Recent logs │
|
|
25
|
+
│ └── Catalog │
|
|
26
|
+
│ │
|
|
27
|
+
│ HTTP POST /v1/sync │
|
|
28
|
+
│ ├── envelope store (config.sink) │
|
|
29
|
+
│ │ null | memory | ndjson │
|
|
30
|
+
│ └── per-project ingest │
|
|
31
|
+
│ aggregator, recent logs, clients │
|
|
32
|
+
│ config reply filtered by client.role │
|
|
33
|
+
└─────────────────────────▲─────────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
frames up / that role's config down
|
|
36
|
+
┌───────────────┴───────────────┐
|
|
37
|
+
▼ ▼
|
|
38
|
+
Node SDK C# / Unity SDK
|
|
39
|
+
wardx / @wardx/core clients/csharp
|
|
40
|
+
role: game-server role: mobile
|
|
41
|
+
metrics / config.get same /v1/sync
|
|
42
|
+
```
|
|
43
|
+
|
|
9
44
|
## Install
|
|
10
45
|
|
|
11
46
|
```bash
|
|
@@ -333,7 +368,7 @@ function grantCoins(wardx, grant) {
|
|
|
333
368
|
2. On the grant path, add the amount to `coins.awarded` and increment `coins.grants`. The dimension is `source`, not a user id.
|
|
334
369
|
3. Observe the amount in `coins.award_size` with a lookup key (`grantId`). The histogram keeps those attrs only for the window max, as `exemplar`. Histogram `max` and the upper buckets are the inconsistency signal. The exemplar is the row to open in the database.
|
|
335
370
|
4. Read `economy.maxAward` from Remote Config. Emit `coins.anomaly` only when a grant exceeds that bound. That event is rare.
|
|
336
|
-
5. From MCP,
|
|
371
|
+
5. From MCP, the overview ranks histogram outcomes by `max` and includes the exemplar. Compare that max and `coins.awarded / coins.grants` (mean grant) against `economy.maxAward`. If max is high, read `exemplar.attrs.grantId`, then `get_recent_logs` with `coins_anomaly` or that `grantId`. If the role has `path` or `git`, search that checkout for `source` / `reason`. See `@wardx/server` use case 9.
|
|
337
372
|
|
|
338
373
|
Do not put `userId` on a counter or histogram dimension. The SDK and the server cap series. A unique id per player creates a series per player and then drops. An exemplar is one sample per series per window, so a lookup key there does not explode cardinality. Do not `event()` once per grant on a backend that serves many users. Use an event only for the anomaly.
|
|
339
374
|
|
|
@@ -530,8 +565,8 @@ On a process that serves many users, skip `identify()` and pass `{ subjectId }`
|
|
|
530
565
|
1. Start a local clock when the play session starts. Do not use `sessionId`.
|
|
531
566
|
2. When it ends, observe `session.duration` with minute-scale buckets. Default histogram buckets are for short durations in milliseconds.
|
|
532
567
|
3. Add the same number to `session.time_ms`. Increment `session.ended`.
|
|
533
|
-
4. Call `experiment.goal('session.duration', { value: durationMs })` with a subject. Emit that goal once per ended session. `analyze_experiment` then has `goalSum` and `
|
|
534
|
-
5. From MCP, read `session.time_ms` in `get_aggregates` for fleet minutes. Compare variants with `analyze_experiment`, not with a counter dimension.
|
|
568
|
+
4. Call `experiment.goal('session.duration', { value: durationMs })` with a subject. Emit that goal once per ended session. `analyze_experiment` then has `goalSum`, `goalMean`, and a `decision` per variant. Mean session ms is `goalSum / goals`.
|
|
569
|
+
5. From MCP, read `session.time_ms` in `get_aggregates` for fleet minutes. Compare variants with `analyze_experiment`, not with a counter dimension. Ship a winner with `ship_experiment`.
|
|
535
570
|
|
|
536
571
|
Do not put `userId` on the histogram. Do not emit `experiment.goal` on every heartbeat: that would count many goals for one session. The heartbeat only adds to `session.time_ms`.
|
|
537
572
|
|
|
@@ -570,7 +605,7 @@ The volume funnel `level.start` → `level.fail` / `level.complete` is the diffi
|
|
|
570
605
|
|
|
571
606
|
Call `experiment.goal('session.duration', { value: durationMs })` when the play session ends (use case 14).
|
|
572
607
|
|
|
573
|
-
From MCP, after onboarding: `upsert_experiment` on the existing keys (`level.3.enemyHp`, …) with a hypothesis such as "Lower HP on level 3 increases session duration", `primaryMetric: 'session.time_ms'`, and variants that only change those keys. Later `analyze_experiment`: compare `goalMean` for the duration goal. Compare the funnel counts with `get_aggregates`. See `@wardx/server` use case 7.
|
|
608
|
+
From MCP, after onboarding: `upsert_experiment` on the existing keys (`level.3.enemyHp`, …) with a hypothesis such as "Lower HP on level 3 increases session duration", `primaryMetric: 'session.time_ms'`, `goalKind: 'mean'`, `control`, `minExposures`, `confidence`, and variants that only change those keys. Later `analyze_experiment`: follow `decision` and compare `goalMean` for the duration goal. `ship_experiment` when status is `winner`. Compare the funnel counts with `get_aggregates`. See `@wardx/server` use case 7.
|
|
574
609
|
|
|
575
610
|
## Use case 16: Surface an error so an agent can open the source
|
|
576
611
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wardx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Node.js SDK for Wardx telemetry, Remote Config, and experiments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wardx",
|
|
@@ -26,12 +26,17 @@
|
|
|
26
26
|
"node": ">=20"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
|
-
".":
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./src/index.d.ts",
|
|
31
|
+
"import": "./src/index.js",
|
|
32
|
+
"default": "./src/index.js"
|
|
33
|
+
}
|
|
30
34
|
},
|
|
35
|
+
"types": "./src/index.d.ts",
|
|
31
36
|
"files": [
|
|
32
37
|
"src"
|
|
33
38
|
],
|
|
34
39
|
"dependencies": {
|
|
35
|
-
"@wardx/core": "0.1.
|
|
40
|
+
"@wardx/core": "0.1.4"
|
|
36
41
|
}
|
|
37
|
-
}
|
|
42
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Attrs,
|
|
3
|
+
ConfigSnapshot,
|
|
4
|
+
ConfigValue,
|
|
5
|
+
CoreSettings,
|
|
6
|
+
CounterHandle,
|
|
7
|
+
CreateWardxOptions,
|
|
8
|
+
DimensionValue,
|
|
9
|
+
Dimensions,
|
|
10
|
+
EventTraceRecord,
|
|
11
|
+
Experiment,
|
|
12
|
+
ExperimentGoalContext,
|
|
13
|
+
ExperimentVariant,
|
|
14
|
+
FrameTraceRecord,
|
|
15
|
+
GaugeHandle,
|
|
16
|
+
HistogramHandle,
|
|
17
|
+
HistogramOptions,
|
|
18
|
+
LogApi,
|
|
19
|
+
LogLevel,
|
|
20
|
+
LogTraceRecord,
|
|
21
|
+
MeasureTraceRecord,
|
|
22
|
+
ResolvedSettings,
|
|
23
|
+
SdkDefaults,
|
|
24
|
+
StopTimer,
|
|
25
|
+
SubjectContext,
|
|
26
|
+
SyncTraceRecord,
|
|
27
|
+
Tracer
|
|
28
|
+
} from '@wardx/core';
|
|
29
|
+
|
|
30
|
+
export type {
|
|
31
|
+
Attrs,
|
|
32
|
+
ConfigSnapshot,
|
|
33
|
+
ConfigValue,
|
|
34
|
+
CoreSettings,
|
|
35
|
+
CounterHandle,
|
|
36
|
+
CreateWardxOptions,
|
|
37
|
+
DimensionValue,
|
|
38
|
+
Dimensions,
|
|
39
|
+
EventTraceRecord,
|
|
40
|
+
Experiment,
|
|
41
|
+
ExperimentGoalContext,
|
|
42
|
+
ExperimentVariant,
|
|
43
|
+
FrameTraceRecord,
|
|
44
|
+
GaugeHandle,
|
|
45
|
+
HistogramHandle,
|
|
46
|
+
HistogramOptions,
|
|
47
|
+
LogApi,
|
|
48
|
+
LogLevel,
|
|
49
|
+
LogTraceRecord,
|
|
50
|
+
MeasureTraceRecord,
|
|
51
|
+
ResolvedSettings,
|
|
52
|
+
SdkDefaults,
|
|
53
|
+
StopTimer,
|
|
54
|
+
SubjectContext,
|
|
55
|
+
SyncTraceRecord,
|
|
56
|
+
Tracer
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export interface ConsoleTracerOptions {
|
|
60
|
+
stream?: { write(chunk: string): unknown };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ConfigApi {
|
|
64
|
+
get<T>(key: string, fallback: T, context?: SubjectContext): T;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ExperimentApi {
|
|
68
|
+
goal(name: string, context?: ExperimentGoalContext): void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class WardxNode {
|
|
72
|
+
settings: ResolvedSettings;
|
|
73
|
+
log: LogApi;
|
|
74
|
+
config: ConfigApi;
|
|
75
|
+
experiment: ExperimentApi;
|
|
76
|
+
constructor(settings: ResolvedSettings);
|
|
77
|
+
identify(subjectId: string | null | undefined): void;
|
|
78
|
+
counter(name: string, dims?: Dimensions | null): CounterHandle;
|
|
79
|
+
gauge(name: string, dims?: Dimensions | null): GaugeHandle;
|
|
80
|
+
histogram(name: string, a?: HistogramOptions | null, b?: HistogramOptions | null): HistogramHandle;
|
|
81
|
+
timer(name: string, dims?: Dimensions | null): StopTimer;
|
|
82
|
+
event(name: string, attrs?: Attrs | null): void;
|
|
83
|
+
flush(): Promise<void>;
|
|
84
|
+
shutdown(): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createWardx(options: CreateWardxOptions): WardxNode;
|
|
88
|
+
export function createConsoleTracer(options?: ConsoleTracerOptions): Tracer;
|