@gigzen/populace 0.1.0 → 1.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.
@@ -1,7 +1,7 @@
1
1
  <!doctype html>
2
2
  <html lang="en"><head><meta charset="utf-8">
3
3
  <meta name="viewport" content="width=device-width, initial-scale=1">
4
- <title>Populace report — Buzz Buzz</title>
4
+ <title>Populace report — Buzz</title>
5
5
  <style>
6
6
  :root{
7
7
  --paper:#F4F5F7;--card:#fff;--ink:#12181D;--body:#3A454E;--muted:#6B7883;
@@ -80,28 +80,28 @@ footer{margin-top:52px;padding-top:20px;border-top:1px solid var(--rule);
80
80
  <div class="wrap">
81
81
 
82
82
  <header>
83
- <h1>Buzz Buzz</h1>
84
- <span class="sub">test environment · 10 simulated people ·
85
- 14m 38s · Sat, 15 Aug 2026 11:18:42 GMT</span>
83
+ <h1>Buzz</h1>
84
+ <span class="sub">test environment · 30 simulated people ·
85
+ 32m 51s · Thu, 20 Aug 2026 16:58:01 GMT</span>
86
86
  </header>
87
87
 
88
88
  <div class="verdict ok">
89
- <h2>No failures across 2030 API calls</h2>
89
+ <h2>No failures across 46885 API calls</h2>
90
90
 
91
91
  </div>
92
92
 
93
93
 
94
94
 
95
95
  <div class="stats">
96
- <div class="stat"><span class="v">2030</span><span class="l">API calls</span></div>
96
+ <div class="stat"><span class="v">46885</span><span class="l">API calls</span></div>
97
97
  <div class="stat"><span class="v" style="color:var(--ok)">0</span><span class="l">failed</span></div>
98
98
  <div class="stat"><span class="v">0.0%</span><span class="l">failure rate</span></div>
99
- <div class="stat"><span class="v">10</span><span class="l">concurrent users</span></div>
99
+ <div class="stat"><span class="v">30</span><span class="l">concurrent users</span></div>
100
100
  <div class="stat"><span class="v">13/13</span><span class="l">coverage</span></div>
101
101
  </div>
102
102
 
103
103
  <section>
104
- <h2>Your API under 10 concurrent users</h2>
104
+ <h2>Your API under 30 concurrent users</h2>
105
105
  <div class="tablewrap">
106
106
  <table>
107
107
  <thead><tr><th>Method</th><th style="text-align:right">Calls</th>
@@ -110,110 +110,119 @@ footer{margin-top:52px;padding-top:20px;border-top:1px solid var(--rule);
110
110
  <tbody>
111
111
  <tr class="">
112
112
  <td class="mono name">reportLocation</td>
113
- <td class="num">892</td>
113
+ <td class="num">20547</td>
114
114
  <td class="num zero">0</td>
115
- <td class="num">711ms</td>
116
- <td class="num">1.0s</td>
117
- <td class="barcell"><div class="bar" style="width:100.0%"></div></td>
115
+ <td class="num">47ms</td>
116
+ <td class="num">72ms</td>
117
+ <td class="barcell"><div class="bar" style="width:37.3%"></div></td>
118
118
  </tr>
119
119
 
120
120
  <tr class="">
121
121
  <td class="mono name">recentPostsByOthers</td>
122
- <td class="num">298</td>
122
+ <td class="num">7021</td>
123
123
  <td class="num zero">0</td>
124
- <td class="num">241ms</td>
125
- <td class="num">349ms</td>
126
- <td class="barcell"><div class="bar" style="width:34.8%"></div></td>
124
+ <td class="num">12ms</td>
125
+ <td class="num">27ms</td>
126
+ <td class="barcell"><div class="bar" style="width:14.0%"></div></td>
127
127
  </tr>
128
128
 
129
129
  <tr class="">
130
130
  <td class="mono name">like</td>
131
- <td class="num">296</td>
131
+ <td class="num">7021</td>
132
132
  <td class="num zero">0</td>
133
- <td class="num">238ms</td>
134
- <td class="num">319ms</td>
135
- <td class="barcell"><div class="bar" style="width:31.8%"></div></td>
133
+ <td class="num">8ms</td>
134
+ <td class="num">16ms</td>
135
+ <td class="barcell"><div class="bar" style="width:8.3%"></div></td>
136
136
  </tr>
137
137
 
138
138
  <tr class="">
139
139
  <td class="mono name">post</td>
140
- <td class="num">139</td>
140
+ <td class="num">3054</td>
141
141
  <td class="num zero">0</td>
142
- <td class="num">240ms</td>
143
- <td class="num">313ms</td>
144
- <td class="barcell"><div class="bar" style="width:31.2%"></div></td>
142
+ <td class="num">12ms</td>
143
+ <td class="num">22ms</td>
144
+ <td class="barcell"><div class="bar" style="width:11.4%"></div></td>
145
145
  </tr>
146
146
 
147
147
  <tr class="">
148
148
  <td class="mono name">comment</td>
149
- <td class="num">123</td>
149
+ <td class="num">2840</td>
150
150
  <td class="num zero">0</td>
151
- <td class="num">243ms</td>
152
- <td class="num">326ms</td>
153
- <td class="barcell"><div class="bar" style="width:32.5%"></div></td>
151
+ <td class="num">7ms</td>
152
+ <td class="num">13ms</td>
153
+ <td class="barcell"><div class="bar" style="width:6.7%"></div></td>
154
154
  </tr>
155
155
 
156
156
  <tr class="">
157
157
  <td class="mono name">openConversation</td>
158
- <td class="num">110</td>
158
+ <td class="num">2713</td>
159
159
  <td class="num zero">0</td>
160
- <td class="num">245ms</td>
161
- <td class="num">336ms</td>
162
- <td class="barcell"><div class="bar" style="width:33.5%"></div></td>
160
+ <td class="num">8ms</td>
161
+ <td class="num">18ms</td>
162
+ <td class="barcell"><div class="bar" style="width:9.3%"></div></td>
163
163
  </tr>
164
164
 
165
165
  <tr class="">
166
166
  <td class="mono name">sendMessage</td>
167
- <td class="num">110</td>
167
+ <td class="num">2713</td>
168
168
  <td class="num zero">0</td>
169
- <td class="num">244ms</td>
170
- <td class="num">351ms</td>
171
- <td class="barcell"><div class="bar" style="width:35.0%"></div></td>
169
+ <td class="num">9ms</td>
170
+ <td class="num">19ms</td>
171
+ <td class="barcell"><div class="bar" style="width:9.8%"></div></td>
172
172
  </tr>
173
173
 
174
174
  <tr class="">
175
175
  <td class="mono name">listGroups</td>
176
- <td class="num">16</td>
176
+ <td class="num">428</td>
177
177
  <td class="num zero">0</td>
178
- <td class="num">250ms</td>
179
- <td class="num">312ms</td>
180
- <td class="barcell"><div class="bar" style="width:31.1%"></div></td>
178
+ <td class="num">8ms</td>
179
+ <td class="num">17ms</td>
180
+ <td class="barcell"><div class="bar" style="width:8.8%"></div></td>
181
181
  </tr>
182
182
 
183
183
  <tr class="">
184
184
  <td class="mono name">joinGroup</td>
185
- <td class="num">16</td>
185
+ <td class="num">428</td>
186
186
  <td class="num zero">0</td>
187
- <td class="num">235ms</td>
188
- <td class="num">311ms</td>
189
- <td class="barcell"><div class="bar" style="width:31.0%"></div></td>
187
+ <td class="num">7ms</td>
188
+ <td class="num">16ms</td>
189
+ <td class="barcell"><div class="bar" style="width:8.3%"></div></td>
190
190
  </tr>
191
191
 
192
192
  <tr class="">
193
193
  <td class="mono name">createUser</td>
194
- <td class="num">10</td>
194
+ <td class="num">30</td>
195
195
  <td class="num zero">0</td>
196
- <td class="num">601ms</td>
197
- <td class="num">834ms</td>
198
- <td class="barcell"><div class="bar" style="width:83.2%"></div></td>
196
+ <td class="num">149ms</td>
197
+ <td class="num">193ms</td>
198
+ <td class="barcell"><div class="bar" style="width:100.0%"></div></td>
199
199
  </tr>
200
200
 
201
201
  <tr class="">
202
202
  <td class="mono name">setProfile</td>
203
- <td class="num">10</td>
203
+ <td class="num">30</td>
204
+ <td class="num zero">0</td>
205
+ <td class="num">16ms</td>
206
+ <td class="num">22ms</td>
207
+ <td class="barcell"><div class="bar" style="width:11.4%"></div></td>
208
+ </tr>
209
+
210
+ <tr class="">
211
+ <td class="mono name">refreshSession</td>
212
+ <td class="num">30</td>
204
213
  <td class="num zero">0</td>
205
- <td class="num">249ms</td>
206
- <td class="num">392ms</td>
207
- <td class="barcell"><div class="bar" style="width:39.1%"></div></td>
214
+ <td class="num">144ms</td>
215
+ <td class="num">190ms</td>
216
+ <td class="barcell"><div class="bar" style="width:98.4%"></div></td>
208
217
  </tr>
209
218
 
210
219
  <tr class="">
211
220
  <td class="mono name">deleteUser</td>
212
- <td class="num">10</td>
221
+ <td class="num">30</td>
213
222
  <td class="num zero">0</td>
214
- <td class="num">320ms</td>
215
- <td class="num">508ms</td>
216
- <td class="barcell"><div class="bar" style="width:50.6%"></div></td>
223
+ <td class="num">16ms</td>
224
+ <td class="num">31ms</td>
225
+ <td class="barcell"><div class="bar" style="width:16.1%"></div></td>
217
226
  </tr>
218
227
  </tbody>
219
228
  </table>
@@ -223,9 +232,9 @@ footer{margin-top:52px;padding-top:20px;border-top:1px solid var(--rule);
223
232
  <section>
224
233
  <h2>What the population did</h2>
225
234
  <div class="panel">
226
- 36 km travelled · 139 posts ·
227
- 296 likes · 123 comments ·
228
- 110 messages · 16 group joins
235
+ 341.9 km travelled · 3054 posts ·
236
+ 7021 likes · 2840 comments ·
237
+ 2713 messages · 428 group joins
229
238
  </div>
230
239
  </section>
231
240
 
@@ -233,7 +242,7 @@ footer{margin-top:52px;padding-top:20px;border-top:1px solid var(--rule);
233
242
 
234
243
  <section>
235
244
  <h2>Cleanup</h2>
236
- <div><div class="chip ok">Cleanup complete — 10 accounts removed</div></div>
245
+ <div><div class="chip ok">Cleanup complete — 30 accounts removed</div></div>
237
246
  </section>
238
247
 
239
248
  <footer>
@@ -1,22 +1,24 @@
1
1
  {
2
2
  "populace": {
3
3
  "version": "0.1.0",
4
- "generatedAt": "2026-08-15T11:32:20.651Z"
4
+ "generatedAt": "2026-08-20T17:29:52.161Z"
5
5
  },
6
6
  "run": {
7
- "app": "Buzz Buzz",
7
+ "app": "Buzz",
8
8
  "adapter": "../../adapters/buzzbuzz.mjs",
9
9
  "environment": "test",
10
- "startedAt": "2026-08-15T11:18:42.515Z",
11
- "durationMs": 818136,
10
+ "startedAt": "2026-08-20T16:58:01.553Z",
11
+ "durationMs": 1910608,
12
12
  "population": {
13
- "agents": 10,
13
+ "agents": 30,
14
14
  "cities": [
15
15
  "manila",
16
- "mumbai"
16
+ "mumbai",
17
+ "delhi",
18
+ "jakarta"
17
19
  ],
18
- "tickSeconds": 5,
19
- "minutes": 10
20
+ "tickSeconds": 2,
21
+ "minutes": 30
20
22
  }
21
23
  },
22
24
  "verdict": {
@@ -27,21 +29,21 @@
27
29
  "failingMethods": []
28
30
  },
29
31
  "population": {
30
- "requested": 10,
31
- "signedIn": 10,
32
+ "requested": 30,
33
+ "signedIn": 30,
32
34
  "signupFailures": []
33
35
  },
34
36
  "engineErrors": [],
35
37
  "activity": {
36
- "distanceKm": 36,
37
- "posts": 139,
38
- "likes": 296,
39
- "comments": 123,
40
- "messages": 110,
41
- "groupJoins": 16
38
+ "distanceKm": 341.9,
39
+ "posts": 3054,
40
+ "likes": 7021,
41
+ "comments": 2840,
42
+ "messages": 2713,
43
+ "groupJoins": 428
42
44
  },
43
45
  "api": {
44
- "calls": 2030,
46
+ "calls": 46885,
45
47
  "failures": 0,
46
48
  "apiFailures": 0,
47
49
  "transportFailures": 0,
@@ -57,197 +59,213 @@
57
59
  "gaveUpAfter": null,
58
60
  "outages": 0
59
61
  },
60
- "durationMs": 818132,
62
+ "durationMs": 1910592,
61
63
  "methods": [
62
64
  {
63
65
  "method": "reportLocation",
64
- "calls": 892,
66
+ "calls": 20547,
65
67
  "failures": 0,
66
68
  "apiFailures": 0,
67
69
  "transportFailures": 0,
68
70
  "retries": 0,
69
71
  "failureRate": 0,
70
72
  "latencyMs": {
71
- "p50": 711,
72
- "p95": 1003,
73
- "p99": 2371,
74
- "max": 3178
73
+ "p50": 47,
74
+ "p95": 72,
75
+ "p99": 102,
76
+ "max": 214
75
77
  },
76
78
  "errors": []
77
79
  },
78
80
  {
79
81
  "method": "recentPostsByOthers",
80
- "calls": 298,
82
+ "calls": 7021,
81
83
  "failures": 0,
82
84
  "apiFailures": 0,
83
85
  "transportFailures": 0,
84
86
  "retries": 0,
85
87
  "failureRate": 0,
86
88
  "latencyMs": {
87
- "p50": 241,
88
- "p95": 349,
89
- "p99": 416,
90
- "max": 622
89
+ "p50": 12,
90
+ "p95": 27,
91
+ "p99": 35,
92
+ "max": 59
91
93
  },
92
94
  "errors": []
93
95
  },
94
96
  {
95
97
  "method": "like",
96
- "calls": 296,
98
+ "calls": 7021,
97
99
  "failures": 0,
98
100
  "apiFailures": 0,
99
101
  "transportFailures": 0,
100
102
  "retries": 0,
101
103
  "failureRate": 0,
102
104
  "latencyMs": {
103
- "p50": 238,
104
- "p95": 319,
105
- "p99": 385,
106
- "max": 760
105
+ "p50": 8,
106
+ "p95": 16,
107
+ "p99": 23,
108
+ "max": 43
107
109
  },
108
110
  "errors": []
109
111
  },
110
112
  {
111
113
  "method": "post",
112
- "calls": 139,
114
+ "calls": 3054,
113
115
  "failures": 0,
114
116
  "apiFailures": 0,
115
117
  "transportFailures": 0,
116
118
  "retries": 0,
117
119
  "failureRate": 0,
118
120
  "latencyMs": {
119
- "p50": 240,
120
- "p95": 313,
121
- "p99": 383,
122
- "max": 614
121
+ "p50": 12,
122
+ "p95": 22,
123
+ "p99": 29,
124
+ "max": 58
123
125
  },
124
126
  "errors": []
125
127
  },
126
128
  {
127
129
  "method": "comment",
128
- "calls": 123,
130
+ "calls": 2840,
129
131
  "failures": 0,
130
132
  "apiFailures": 0,
131
133
  "transportFailures": 0,
132
134
  "retries": 0,
133
135
  "failureRate": 0,
134
136
  "latencyMs": {
135
- "p50": 243,
136
- "p95": 326,
137
- "p99": 387,
138
- "max": 683
137
+ "p50": 7,
138
+ "p95": 13,
139
+ "p99": 19,
140
+ "max": 35
139
141
  },
140
142
  "errors": []
141
143
  },
142
144
  {
143
145
  "method": "openConversation",
144
- "calls": 110,
146
+ "calls": 2713,
145
147
  "failures": 0,
146
148
  "apiFailures": 0,
147
149
  "transportFailures": 0,
148
150
  "retries": 0,
149
151
  "failureRate": 0,
150
152
  "latencyMs": {
151
- "p50": 245,
152
- "p95": 336,
153
- "p99": 375,
154
- "max": 626
153
+ "p50": 8,
154
+ "p95": 18,
155
+ "p99": 25,
156
+ "max": 53
155
157
  },
156
158
  "errors": []
157
159
  },
158
160
  {
159
161
  "method": "sendMessage",
160
- "calls": 110,
162
+ "calls": 2713,
161
163
  "failures": 0,
162
164
  "apiFailures": 0,
163
165
  "transportFailures": 0,
164
166
  "retries": 0,
165
167
  "failureRate": 0,
166
168
  "latencyMs": {
167
- "p50": 244,
168
- "p95": 351,
169
- "p99": 393,
170
- "max": 780
169
+ "p50": 9,
170
+ "p95": 19,
171
+ "p99": 23,
172
+ "max": 32
171
173
  },
172
174
  "errors": []
173
175
  },
174
176
  {
175
177
  "method": "listGroups",
176
- "calls": 16,
178
+ "calls": 428,
177
179
  "failures": 0,
178
180
  "apiFailures": 0,
179
181
  "transportFailures": 0,
180
182
  "retries": 0,
181
183
  "failureRate": 0,
182
184
  "latencyMs": {
183
- "p50": 250,
184
- "p95": 312,
185
- "p99": 312,
186
- "max": 312
185
+ "p50": 8,
186
+ "p95": 17,
187
+ "p99": 22,
188
+ "max": 44
187
189
  },
188
190
  "errors": []
189
191
  },
190
192
  {
191
193
  "method": "joinGroup",
192
- "calls": 16,
194
+ "calls": 428,
193
195
  "failures": 0,
194
196
  "apiFailures": 0,
195
197
  "transportFailures": 0,
196
198
  "retries": 0,
197
199
  "failureRate": 0,
198
200
  "latencyMs": {
199
- "p50": 235,
200
- "p95": 311,
201
- "p99": 311,
202
- "max": 311
201
+ "p50": 7,
202
+ "p95": 16,
203
+ "p99": 20,
204
+ "max": 28
203
205
  },
204
206
  "errors": []
205
207
  },
206
208
  {
207
209
  "method": "createUser",
208
- "calls": 10,
210
+ "calls": 30,
209
211
  "failures": 0,
210
212
  "apiFailures": 0,
211
213
  "transportFailures": 0,
212
214
  "retries": 0,
213
215
  "failureRate": 0,
214
216
  "latencyMs": {
215
- "p50": 601,
216
- "p95": 834,
217
- "p99": 834,
218
- "max": 834
217
+ "p50": 149,
218
+ "p95": 193,
219
+ "p99": 312,
220
+ "max": 312
219
221
  },
220
222
  "errors": []
221
223
  },
222
224
  {
223
225
  "method": "setProfile",
224
- "calls": 10,
226
+ "calls": 30,
227
+ "failures": 0,
228
+ "apiFailures": 0,
229
+ "transportFailures": 0,
230
+ "retries": 0,
231
+ "failureRate": 0,
232
+ "latencyMs": {
233
+ "p50": 16,
234
+ "p95": 22,
235
+ "p99": 23,
236
+ "max": 23
237
+ },
238
+ "errors": []
239
+ },
240
+ {
241
+ "method": "refreshSession",
242
+ "calls": 30,
225
243
  "failures": 0,
226
244
  "apiFailures": 0,
227
245
  "transportFailures": 0,
228
246
  "retries": 0,
229
247
  "failureRate": 0,
230
248
  "latencyMs": {
231
- "p50": 249,
232
- "p95": 392,
233
- "p99": 392,
234
- "max": 392
249
+ "p50": 144,
250
+ "p95": 190,
251
+ "p99": 194,
252
+ "max": 194
235
253
  },
236
254
  "errors": []
237
255
  },
238
256
  {
239
257
  "method": "deleteUser",
240
- "calls": 10,
258
+ "calls": 30,
241
259
  "failures": 0,
242
260
  "apiFailures": 0,
243
261
  "transportFailures": 0,
244
262
  "retries": 0,
245
263
  "failureRate": 0,
246
264
  "latencyMs": {
247
- "p50": 320,
248
- "p95": 508,
249
- "p99": 508,
250
- "max": 508
265
+ "p50": 16,
266
+ "p95": 31,
267
+ "p99": 60,
268
+ "max": 60
251
269
  },
252
270
  "errors": []
253
271
  }
@@ -273,7 +291,7 @@
273
291
  "notTested": []
274
292
  },
275
293
  "cleanup": {
276
- "removed": 10,
294
+ "removed": 30,
277
295
  "notDeleted": [],
278
296
  "failed": []
279
297
  }
@@ -1,4 +1,4 @@
1
- // Populace's first customer: Buzz Buzz, a gig-driver tracking app.
1
+ // Populace's first customer: Buzz, a gig-driver tracking app.
2
2
  //
3
3
  // Run it — PowerShell (Windows):
4
4
  // $env:BUZZBUZZ_TEST_URL="https://<your-TEST-project>.supabase.co"
@@ -17,7 +17,7 @@
17
17
  // otherwise nobody can sign in after signing up.
18
18
 
19
19
  export default {
20
- app: "Buzz Buzz",
20
+ app: "Buzz",
21
21
  adapter: "../../adapters/buzzbuzz.mjs",
22
22
  environment: "test",
23
23
 
@@ -26,7 +26,7 @@ export default {
26
26
  key: process.env.BUZZBUZZ_TEST_KEY,
27
27
  },
28
28
 
29
- // Buzz Buzz's LIVE project. If BUZZBUZZ_TEST_URL is ever set to this by
29
+ // Buzz's LIVE project. If BUZZBUZZ_TEST_URL is ever set to this by
30
30
  // accident, Populace refuses to start. Real drivers must never see invented
31
31
  // people on their map.
32
32
  // Both of these are real. rqzuuvlougzhynckvqzd is the original project, which
@@ -1,4 +1,4 @@
1
- # Run the Buzz Buzz simulation from Windows PowerShell.
1
+ # Run the Buzz simulation from Windows PowerShell.
2
2
  #
3
3
  # Exists because the bash one-liner does not work here: PowerShell 5.1 has no
4
4
  # `&&` statement separator and no `VAR=value command` prefix, so pasting the
@@ -29,9 +29,9 @@ test · 6 people · 124.7s
29
29
 
30
30
  ## Why this proves something
31
31
 
32
- The server disagrees with Buzz Buzz on every axis that could hide an assumption:
32
+ The server disagrees with Buzz on every axis that could hide an assumption:
33
33
 
34
- | | Buzz Buzz | this server |
34
+ | | Buzz | this server |
35
35
  |---|---|---|
36
36
  | transport | `supabase-js` client | plain `fetch` |
37
37
  | ids | UUID strings | **integers** |
@@ -11,11 +11,14 @@
11
11
  */
12
12
 
13
13
  export function createAdapter(target) {
14
+ if (!target?.url) {
15
+ throw new Error("No target URL. Set `target.url` in populace.config.mjs.");
16
+ }
14
17
  const base = target.url.replace(/\/$/, "");
15
18
 
16
19
  /**
17
20
  * The contract hands an adapter a name, a phone and a persona — never a
18
- * password. Choosing one is the adapter's job, exactly as the Buzz Buzz
21
+ * password. Choosing one is the adapter's job, exactly as the Buzz
19
22
  * reference adapter does, because only you know what your API will accept.
20
23
  *
21
24
  * A constant is right here: identities are deterministic so that a re-run
@@ -74,7 +77,7 @@ export function createAdapter(target) {
74
77
  body: { phone, password: PASSWORD, name },
75
78
  });
76
79
  // The handle is whatever later calls need. Here that is an integer id and
77
- // a token; for Buzz Buzz it was a UUID and a client object. The engine
80
+ // a token; for Buzz it was a UUID and a client object. The engine
78
81
  // only ever reads `.id`.
79
82
  return { id: out.id, token: out.token };
80
83
  },