@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.
- package/README.md +227 -10
- package/action.yml +145 -0
- package/adapters/buzzbuzz.mjs +1 -1
- package/adapters/template-rest.mjs +16 -0
- package/examples/buzzbuzz/populace-report.html +69 -60
- package/examples/buzzbuzz/populace-report.json +97 -79
- package/examples/buzzbuzz/populace.config.mjs +3 -3
- package/examples/buzzbuzz/run-test.ps1 +1 -1
- package/examples/rest-api/README.md +2 -2
- package/examples/rest-api/adapter.mjs +5 -2
- package/examples/rest-api/populace-report.html +245 -0
- package/examples/rest-api/populace-report.json +280 -0
- package/examples/rest-api/server.mjs +4 -4
- package/package.json +3 -2
- package/src/ai.mjs +158 -0
- package/src/cli.mjs +139 -2
- package/src/engine/personas.mjs +654 -11
- package/src/engine/world.mjs +3 -3
- package/src/explain.mjs +247 -0
- package/src/github-summary.mjs +152 -0
- package/src/openapi.mjs +322 -0
- package/src/report.mjs +37 -0
- package/src/selftest.mjs +251 -0
- package/src/update.mjs +141 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8">
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
4
|
+
<title>Populace report — REST API demo</title>
|
|
5
|
+
<style>
|
|
6
|
+
:root{
|
|
7
|
+
--paper:#F4F5F7;--card:#fff;--ink:#12181D;--body:#3A454E;--muted:#6B7883;
|
|
8
|
+
--rule:#DDE2E7;--accent:#A85A0B;--ok:#2C6E4C;--bad:#A63127;--warn:#9A6A08;
|
|
9
|
+
--bar:#C9D4DC;--barbad:#E0A99F;
|
|
10
|
+
--mono:ui-monospace,"SF Mono","Cascadia Mono",Menlo,Consolas,monospace;
|
|
11
|
+
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;
|
|
12
|
+
}
|
|
13
|
+
@media (prefers-color-scheme:dark){:root{
|
|
14
|
+
--paper:#0E1418;--card:#161E24;--ink:#E8EEF3;--body:#B0BDC7;--muted:#7B8994;
|
|
15
|
+
--rule:#26323A;--accent:#E0A45C;--ok:#5FAB80;--bad:#DE7568;--warn:#D2A24E;
|
|
16
|
+
--bar:#2E3A43;--barbad:#5C332C;}}
|
|
17
|
+
:root[data-theme="dark"]{--paper:#0E1418;--card:#161E24;--ink:#E8EEF3;--body:#B0BDC7;
|
|
18
|
+
--muted:#7B8994;--rule:#26323A;--accent:#E0A45C;--ok:#5FAB80;--bad:#DE7568;
|
|
19
|
+
--warn:#D2A24E;--bar:#2E3A43;--barbad:#5C332C;}
|
|
20
|
+
:root[data-theme="light"]{--paper:#F4F5F7;--card:#fff;--ink:#12181D;--body:#3A454E;
|
|
21
|
+
--muted:#6B7883;--rule:#DDE2E7;--accent:#A85A0B;--ok:#2C6E4C;--bad:#A63127;
|
|
22
|
+
--warn:#9A6A08;--bar:#C9D4DC;--barbad:#E0A99F;}
|
|
23
|
+
*{box-sizing:border-box}
|
|
24
|
+
body{margin:0;background:var(--paper);color:var(--body);font-family:var(--sans);
|
|
25
|
+
font-size:15.5px;line-height:1.6;-webkit-font-smoothing:antialiased}
|
|
26
|
+
.wrap{max-width:900px;margin:0 auto;padding:0 22px 80px}
|
|
27
|
+
h1,h2,h3{color:var(--ink);margin:0;text-wrap:balance}
|
|
28
|
+
h1{font-family:var(--mono);font-size:clamp(22px,4vw,30px);letter-spacing:-.02em}
|
|
29
|
+
h2{font-size:17px;font-family:var(--mono);letter-spacing:-.01em}
|
|
30
|
+
.mono{font-family:var(--mono)}
|
|
31
|
+
header{padding:44px 0 24px;border-bottom:2px solid var(--ink);display:flex;
|
|
32
|
+
flex-direction:column;gap:10px}
|
|
33
|
+
.sub{font-family:var(--mono);font-size:12.5px;color:var(--muted)}
|
|
34
|
+
.verdict{margin-top:26px;padding:20px 22px;border-radius:6px;display:flex;
|
|
35
|
+
flex-direction:column;gap:8px;border-left:4px solid}
|
|
36
|
+
.verdict.ok{background:color-mix(in srgb,var(--ok) 8%,transparent);border-color:var(--ok)}
|
|
37
|
+
.verdict.bad{background:color-mix(in srgb,var(--bad) 8%,transparent);border-color:var(--bad)}
|
|
38
|
+
.verdict h2{color:var(--ink)}
|
|
39
|
+
.verdict ul{margin:4px 0 0;padding-left:20px}
|
|
40
|
+
.stats{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));margin-top:26px}
|
|
41
|
+
.stat{background:var(--card);border:1px solid var(--rule);border-radius:6px;padding:15px 16px}
|
|
42
|
+
.stat .v{font-family:var(--mono);font-size:23px;color:var(--ink);font-weight:600;
|
|
43
|
+
letter-spacing:-.02em;font-variant-numeric:tabular-nums;display:block}
|
|
44
|
+
.stat .l{font-family:var(--mono);font-size:10px;letter-spacing:.12em;
|
|
45
|
+
text-transform:uppercase;color:var(--muted)}
|
|
46
|
+
section{margin-top:42px;display:flex;flex-direction:column;gap:14px}
|
|
47
|
+
.panel{background:var(--card);border:1px solid var(--rule);border-radius:6px;padding:20px 22px}
|
|
48
|
+
.panel.danger{border-color:var(--bad);border-left-width:4px}
|
|
49
|
+
.panel.danger h2{color:var(--bad)}
|
|
50
|
+
.tablewrap{overflow-x:auto;border:1px solid var(--rule);border-radius:6px;background:var(--card)}
|
|
51
|
+
table{border-collapse:collapse;width:100%;min-width:600px}
|
|
52
|
+
th,td{padding:10px 14px;text-align:left;border-bottom:1px solid var(--rule)}
|
|
53
|
+
th{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
|
|
54
|
+
color:var(--muted);font-weight:600}
|
|
55
|
+
td.num{text-align:right;font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:13.5px}
|
|
56
|
+
td.name{font-size:13.5px;color:var(--ink);white-space:nowrap}
|
|
57
|
+
td.zero{color:var(--muted)}
|
|
58
|
+
td.fail{color:var(--bad);font-weight:600}
|
|
59
|
+
.x{color:var(--bad);margin-right:6px}
|
|
60
|
+
.barcell{width:120px}
|
|
61
|
+
.bar{height:7px;background:var(--bar);border-radius:4px}
|
|
62
|
+
.row-bad .bar{background:var(--barbad)}
|
|
63
|
+
tr.errrow td{padding-top:0;border-bottom:1px solid var(--rule)}
|
|
64
|
+
.err{font-family:var(--mono);font-size:12px;color:var(--bad);padding:3px 0 3px 26px}
|
|
65
|
+
.errn{color:var(--muted);margin-right:8px}
|
|
66
|
+
.trace{font-family:var(--mono);font-size:11.5px;white-space:pre-wrap;overflow-x:auto;
|
|
67
|
+
background:var(--paper);padding:14px;border-radius:5px;margin:0;color:var(--body)}
|
|
68
|
+
ul.cov{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:9px}
|
|
69
|
+
ul.cov li{display:flex;gap:14px;flex-wrap:wrap;align-items:baseline;font-size:14px}
|
|
70
|
+
ul.cov .mono{color:var(--ink);min-width:170px;font-size:13px}
|
|
71
|
+
.would{color:var(--muted);font-size:13.5px}
|
|
72
|
+
.chip{display:inline-block;font-family:var(--mono);font-size:12px;padding:7px 13px;
|
|
73
|
+
border-radius:5px;border:1px solid}
|
|
74
|
+
.chip.ok{color:var(--ok);border-color:var(--ok);background:color-mix(in srgb,var(--ok) 8%,transparent)}
|
|
75
|
+
.chip.bad{color:var(--bad);border-color:var(--bad);background:color-mix(in srgb,var(--bad) 8%,transparent)}
|
|
76
|
+
.chip.warn{color:var(--warn);border-color:var(--warn);background:color-mix(in srgb,var(--warn) 8%,transparent)}
|
|
77
|
+
footer{margin-top:52px;padding-top:20px;border-top:1px solid var(--rule);
|
|
78
|
+
font-size:13px;color:var(--muted);display:flex;flex-direction:column;gap:6px}
|
|
79
|
+
</style></head><body>
|
|
80
|
+
<div class="wrap">
|
|
81
|
+
|
|
82
|
+
<header>
|
|
83
|
+
<h1>REST API demo</h1>
|
|
84
|
+
<span class="sub">test environment · 6 simulated people ·
|
|
85
|
+
2m 5s · Sat, 15 Aug 2026 13:40:33 GMT</span>
|
|
86
|
+
</header>
|
|
87
|
+
|
|
88
|
+
<div class="verdict ok">
|
|
89
|
+
<h2>No failures across 444 API calls</h2>
|
|
90
|
+
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
<div class="stats">
|
|
96
|
+
<div class="stat"><span class="v">444</span><span class="l">API calls</span></div>
|
|
97
|
+
<div class="stat"><span class="v" style="color:var(--ok)">0</span><span class="l">failed</span></div>
|
|
98
|
+
<div class="stat"><span class="v">0.0%</span><span class="l">failure rate</span></div>
|
|
99
|
+
<div class="stat"><span class="v">6</span><span class="l">concurrent users</span></div>
|
|
100
|
+
<div class="stat"><span class="v">13/13</span><span class="l">coverage</span></div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<section>
|
|
104
|
+
<h2>Your API under 6 concurrent users</h2>
|
|
105
|
+
<div class="tablewrap">
|
|
106
|
+
<table>
|
|
107
|
+
<thead><tr><th>Method</th><th style="text-align:right">Calls</th>
|
|
108
|
+
<th style="text-align:right">Fails</th><th style="text-align:right">p50</th>
|
|
109
|
+
<th style="text-align:right">p95</th><th>p95 relative</th></tr></thead>
|
|
110
|
+
<tbody>
|
|
111
|
+
<tr class="">
|
|
112
|
+
<td class="mono name">reportLocation</td>
|
|
113
|
+
<td class="num">187</td>
|
|
114
|
+
<td class="num zero">0</td>
|
|
115
|
+
<td class="num">5ms</td>
|
|
116
|
+
<td class="num">9ms</td>
|
|
117
|
+
<td class="barcell"><div class="bar" style="width:27.3%"></div></td>
|
|
118
|
+
</tr>
|
|
119
|
+
|
|
120
|
+
<tr class="">
|
|
121
|
+
<td class="mono name">recentPostsByOthers</td>
|
|
122
|
+
<td class="num">63</td>
|
|
123
|
+
<td class="num zero">0</td>
|
|
124
|
+
<td class="num">3ms</td>
|
|
125
|
+
<td class="num">6ms</td>
|
|
126
|
+
<td class="barcell"><div class="bar" style="width:18.2%"></div></td>
|
|
127
|
+
</tr>
|
|
128
|
+
|
|
129
|
+
<tr class="">
|
|
130
|
+
<td class="mono name">like</td>
|
|
131
|
+
<td class="num">63</td>
|
|
132
|
+
<td class="num zero">0</td>
|
|
133
|
+
<td class="num">4ms</td>
|
|
134
|
+
<td class="num">10ms</td>
|
|
135
|
+
<td class="barcell"><div class="bar" style="width:30.3%"></div></td>
|
|
136
|
+
</tr>
|
|
137
|
+
|
|
138
|
+
<tr class="">
|
|
139
|
+
<td class="mono name">post</td>
|
|
140
|
+
<td class="num">29</td>
|
|
141
|
+
<td class="num zero">0</td>
|
|
142
|
+
<td class="num">3ms</td>
|
|
143
|
+
<td class="num">5ms</td>
|
|
144
|
+
<td class="barcell"><div class="bar" style="width:15.2%"></div></td>
|
|
145
|
+
</tr>
|
|
146
|
+
|
|
147
|
+
<tr class="">
|
|
148
|
+
<td class="mono name">comment</td>
|
|
149
|
+
<td class="num">28</td>
|
|
150
|
+
<td class="num zero">0</td>
|
|
151
|
+
<td class="num">3ms</td>
|
|
152
|
+
<td class="num">20ms</td>
|
|
153
|
+
<td class="barcell"><div class="bar" style="width:60.6%"></div></td>
|
|
154
|
+
</tr>
|
|
155
|
+
|
|
156
|
+
<tr class="">
|
|
157
|
+
<td class="mono name">openConversation</td>
|
|
158
|
+
<td class="num">26</td>
|
|
159
|
+
<td class="num zero">0</td>
|
|
160
|
+
<td class="num">3ms</td>
|
|
161
|
+
<td class="num">15ms</td>
|
|
162
|
+
<td class="barcell"><div class="bar" style="width:45.5%"></div></td>
|
|
163
|
+
</tr>
|
|
164
|
+
|
|
165
|
+
<tr class="">
|
|
166
|
+
<td class="mono name">sendMessage</td>
|
|
167
|
+
<td class="num">26</td>
|
|
168
|
+
<td class="num zero">0</td>
|
|
169
|
+
<td class="num">5ms</td>
|
|
170
|
+
<td class="num">16ms</td>
|
|
171
|
+
<td class="barcell"><div class="bar" style="width:48.5%"></div></td>
|
|
172
|
+
</tr>
|
|
173
|
+
|
|
174
|
+
<tr class="">
|
|
175
|
+
<td class="mono name">createUser</td>
|
|
176
|
+
<td class="num">6</td>
|
|
177
|
+
<td class="num zero">0</td>
|
|
178
|
+
<td class="num">9ms</td>
|
|
179
|
+
<td class="num">33ms</td>
|
|
180
|
+
<td class="barcell"><div class="bar" style="width:100.0%"></div></td>
|
|
181
|
+
</tr>
|
|
182
|
+
|
|
183
|
+
<tr class="">
|
|
184
|
+
<td class="mono name">setProfile</td>
|
|
185
|
+
<td class="num">6</td>
|
|
186
|
+
<td class="num zero">0</td>
|
|
187
|
+
<td class="num">3ms</td>
|
|
188
|
+
<td class="num">16ms</td>
|
|
189
|
+
<td class="barcell"><div class="bar" style="width:48.5%"></div></td>
|
|
190
|
+
</tr>
|
|
191
|
+
|
|
192
|
+
<tr class="">
|
|
193
|
+
<td class="mono name">deleteUser</td>
|
|
194
|
+
<td class="num">6</td>
|
|
195
|
+
<td class="num zero">0</td>
|
|
196
|
+
<td class="num">1ms</td>
|
|
197
|
+
<td class="num">3ms</td>
|
|
198
|
+
<td class="barcell"><div class="bar" style="width:9.1%"></div></td>
|
|
199
|
+
</tr>
|
|
200
|
+
|
|
201
|
+
<tr class="">
|
|
202
|
+
<td class="mono name">listGroups</td>
|
|
203
|
+
<td class="num">2</td>
|
|
204
|
+
<td class="num zero">0</td>
|
|
205
|
+
<td class="num">1ms</td>
|
|
206
|
+
<td class="num">2ms</td>
|
|
207
|
+
<td class="barcell"><div class="bar" style="width:6.1%"></div></td>
|
|
208
|
+
</tr>
|
|
209
|
+
|
|
210
|
+
<tr class="">
|
|
211
|
+
<td class="mono name">joinGroup</td>
|
|
212
|
+
<td class="num">2</td>
|
|
213
|
+
<td class="num zero">0</td>
|
|
214
|
+
<td class="num">1ms</td>
|
|
215
|
+
<td class="num">1ms</td>
|
|
216
|
+
<td class="barcell"><div class="bar" style="width:3.0%"></div></td>
|
|
217
|
+
</tr>
|
|
218
|
+
</tbody>
|
|
219
|
+
</table>
|
|
220
|
+
</div>
|
|
221
|
+
</section>
|
|
222
|
+
|
|
223
|
+
<section>
|
|
224
|
+
<h2>What the population did</h2>
|
|
225
|
+
<div class="panel">
|
|
226
|
+
4.4 km travelled · 29 posts ·
|
|
227
|
+
63 likes · 28 comments ·
|
|
228
|
+
26 messages · 2 group joins
|
|
229
|
+
</div>
|
|
230
|
+
</section>
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
<section>
|
|
235
|
+
<h2>Cleanup</h2>
|
|
236
|
+
<div><div class="chip ok">Cleanup complete — 6 accounts removed</div></div>
|
|
237
|
+
</section>
|
|
238
|
+
|
|
239
|
+
<footer>
|
|
240
|
+
<span>Generated by Populace 0.1.0 · adapter <span class="mono">./adapter.mjs</span></span>
|
|
241
|
+
<span>Simulated people are generated from patterns. This report shows whether your app
|
|
242
|
+
<strong>works</strong> — not whether anyone wants it.</span>
|
|
243
|
+
</footer>
|
|
244
|
+
|
|
245
|
+
</div></body></html>
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
{
|
|
2
|
+
"populace": {
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"generatedAt": "2026-08-15T13:42:37.781Z"
|
|
5
|
+
},
|
|
6
|
+
"run": {
|
|
7
|
+
"app": "REST API demo",
|
|
8
|
+
"adapter": "./adapter.mjs",
|
|
9
|
+
"environment": "test",
|
|
10
|
+
"startedAt": "2026-08-15T13:40:33.054Z",
|
|
11
|
+
"durationMs": 124728,
|
|
12
|
+
"population": {
|
|
13
|
+
"agents": 6,
|
|
14
|
+
"cities": [
|
|
15
|
+
"manila",
|
|
16
|
+
"mumbai"
|
|
17
|
+
],
|
|
18
|
+
"tickSeconds": 3,
|
|
19
|
+
"minutes": 2
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"verdict": {
|
|
23
|
+
"status": "clean",
|
|
24
|
+
"problems": [],
|
|
25
|
+
"apiFailures": 0,
|
|
26
|
+
"transportFailures": 0,
|
|
27
|
+
"failingMethods": []
|
|
28
|
+
},
|
|
29
|
+
"population": {
|
|
30
|
+
"requested": 6,
|
|
31
|
+
"signedIn": 6,
|
|
32
|
+
"signupFailures": []
|
|
33
|
+
},
|
|
34
|
+
"engineErrors": [],
|
|
35
|
+
"activity": {
|
|
36
|
+
"distanceKm": 4.4,
|
|
37
|
+
"posts": 29,
|
|
38
|
+
"likes": 63,
|
|
39
|
+
"comments": 28,
|
|
40
|
+
"messages": 26,
|
|
41
|
+
"groupJoins": 2
|
|
42
|
+
},
|
|
43
|
+
"api": {
|
|
44
|
+
"calls": 444,
|
|
45
|
+
"failures": 0,
|
|
46
|
+
"apiFailures": 0,
|
|
47
|
+
"transportFailures": 0,
|
|
48
|
+
"retries": 0,
|
|
49
|
+
"failureRate": 0,
|
|
50
|
+
"apiFailureRate": 0,
|
|
51
|
+
"network": {
|
|
52
|
+
"retries": 0,
|
|
53
|
+
"transportFailures": 0,
|
|
54
|
+
"retryRate": 0,
|
|
55
|
+
"healthy": true,
|
|
56
|
+
"gaveUp": false,
|
|
57
|
+
"gaveUpAfter": null,
|
|
58
|
+
"outages": 0
|
|
59
|
+
},
|
|
60
|
+
"durationMs": 124726,
|
|
61
|
+
"methods": [
|
|
62
|
+
{
|
|
63
|
+
"method": "reportLocation",
|
|
64
|
+
"calls": 187,
|
|
65
|
+
"failures": 0,
|
|
66
|
+
"apiFailures": 0,
|
|
67
|
+
"transportFailures": 0,
|
|
68
|
+
"retries": 0,
|
|
69
|
+
"failureRate": 0,
|
|
70
|
+
"latencyMs": {
|
|
71
|
+
"p50": 5,
|
|
72
|
+
"p95": 9,
|
|
73
|
+
"p99": 14,
|
|
74
|
+
"max": 14
|
|
75
|
+
},
|
|
76
|
+
"errors": []
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"method": "recentPostsByOthers",
|
|
80
|
+
"calls": 63,
|
|
81
|
+
"failures": 0,
|
|
82
|
+
"apiFailures": 0,
|
|
83
|
+
"transportFailures": 0,
|
|
84
|
+
"retries": 0,
|
|
85
|
+
"failureRate": 0,
|
|
86
|
+
"latencyMs": {
|
|
87
|
+
"p50": 3,
|
|
88
|
+
"p95": 6,
|
|
89
|
+
"p99": 10,
|
|
90
|
+
"max": 10
|
|
91
|
+
},
|
|
92
|
+
"errors": []
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"method": "like",
|
|
96
|
+
"calls": 63,
|
|
97
|
+
"failures": 0,
|
|
98
|
+
"apiFailures": 0,
|
|
99
|
+
"transportFailures": 0,
|
|
100
|
+
"retries": 0,
|
|
101
|
+
"failureRate": 0,
|
|
102
|
+
"latencyMs": {
|
|
103
|
+
"p50": 4,
|
|
104
|
+
"p95": 10,
|
|
105
|
+
"p99": 16,
|
|
106
|
+
"max": 16
|
|
107
|
+
},
|
|
108
|
+
"errors": []
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"method": "post",
|
|
112
|
+
"calls": 29,
|
|
113
|
+
"failures": 0,
|
|
114
|
+
"apiFailures": 0,
|
|
115
|
+
"transportFailures": 0,
|
|
116
|
+
"retries": 0,
|
|
117
|
+
"failureRate": 0,
|
|
118
|
+
"latencyMs": {
|
|
119
|
+
"p50": 3,
|
|
120
|
+
"p95": 5,
|
|
121
|
+
"p99": 5,
|
|
122
|
+
"max": 5
|
|
123
|
+
},
|
|
124
|
+
"errors": []
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"method": "comment",
|
|
128
|
+
"calls": 28,
|
|
129
|
+
"failures": 0,
|
|
130
|
+
"apiFailures": 0,
|
|
131
|
+
"transportFailures": 0,
|
|
132
|
+
"retries": 0,
|
|
133
|
+
"failureRate": 0,
|
|
134
|
+
"latencyMs": {
|
|
135
|
+
"p50": 3,
|
|
136
|
+
"p95": 20,
|
|
137
|
+
"p99": 22,
|
|
138
|
+
"max": 22
|
|
139
|
+
},
|
|
140
|
+
"errors": []
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"method": "openConversation",
|
|
144
|
+
"calls": 26,
|
|
145
|
+
"failures": 0,
|
|
146
|
+
"apiFailures": 0,
|
|
147
|
+
"transportFailures": 0,
|
|
148
|
+
"retries": 0,
|
|
149
|
+
"failureRate": 0,
|
|
150
|
+
"latencyMs": {
|
|
151
|
+
"p50": 3,
|
|
152
|
+
"p95": 15,
|
|
153
|
+
"p99": 16,
|
|
154
|
+
"max": 16
|
|
155
|
+
},
|
|
156
|
+
"errors": []
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"method": "sendMessage",
|
|
160
|
+
"calls": 26,
|
|
161
|
+
"failures": 0,
|
|
162
|
+
"apiFailures": 0,
|
|
163
|
+
"transportFailures": 0,
|
|
164
|
+
"retries": 0,
|
|
165
|
+
"failureRate": 0,
|
|
166
|
+
"latencyMs": {
|
|
167
|
+
"p50": 5,
|
|
168
|
+
"p95": 16,
|
|
169
|
+
"p99": 16,
|
|
170
|
+
"max": 16
|
|
171
|
+
},
|
|
172
|
+
"errors": []
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"method": "createUser",
|
|
176
|
+
"calls": 6,
|
|
177
|
+
"failures": 0,
|
|
178
|
+
"apiFailures": 0,
|
|
179
|
+
"transportFailures": 0,
|
|
180
|
+
"retries": 0,
|
|
181
|
+
"failureRate": 0,
|
|
182
|
+
"latencyMs": {
|
|
183
|
+
"p50": 9,
|
|
184
|
+
"p95": 33,
|
|
185
|
+
"p99": 33,
|
|
186
|
+
"max": 33
|
|
187
|
+
},
|
|
188
|
+
"errors": []
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"method": "setProfile",
|
|
192
|
+
"calls": 6,
|
|
193
|
+
"failures": 0,
|
|
194
|
+
"apiFailures": 0,
|
|
195
|
+
"transportFailures": 0,
|
|
196
|
+
"retries": 0,
|
|
197
|
+
"failureRate": 0,
|
|
198
|
+
"latencyMs": {
|
|
199
|
+
"p50": 3,
|
|
200
|
+
"p95": 16,
|
|
201
|
+
"p99": 16,
|
|
202
|
+
"max": 16
|
|
203
|
+
},
|
|
204
|
+
"errors": []
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"method": "deleteUser",
|
|
208
|
+
"calls": 6,
|
|
209
|
+
"failures": 0,
|
|
210
|
+
"apiFailures": 0,
|
|
211
|
+
"transportFailures": 0,
|
|
212
|
+
"retries": 0,
|
|
213
|
+
"failureRate": 0,
|
|
214
|
+
"latencyMs": {
|
|
215
|
+
"p50": 1,
|
|
216
|
+
"p95": 3,
|
|
217
|
+
"p99": 3,
|
|
218
|
+
"max": 3
|
|
219
|
+
},
|
|
220
|
+
"errors": []
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"method": "listGroups",
|
|
224
|
+
"calls": 2,
|
|
225
|
+
"failures": 0,
|
|
226
|
+
"apiFailures": 0,
|
|
227
|
+
"transportFailures": 0,
|
|
228
|
+
"retries": 0,
|
|
229
|
+
"failureRate": 0,
|
|
230
|
+
"latencyMs": {
|
|
231
|
+
"p50": 1,
|
|
232
|
+
"p95": 2,
|
|
233
|
+
"p99": 2,
|
|
234
|
+
"max": 2
|
|
235
|
+
},
|
|
236
|
+
"errors": []
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"method": "joinGroup",
|
|
240
|
+
"calls": 2,
|
|
241
|
+
"failures": 0,
|
|
242
|
+
"apiFailures": 0,
|
|
243
|
+
"transportFailures": 0,
|
|
244
|
+
"retries": 0,
|
|
245
|
+
"failureRate": 0,
|
|
246
|
+
"latencyMs": {
|
|
247
|
+
"p50": 1,
|
|
248
|
+
"p95": 1,
|
|
249
|
+
"p99": 1,
|
|
250
|
+
"max": 1
|
|
251
|
+
},
|
|
252
|
+
"errors": []
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
"coverage": {
|
|
257
|
+
"label": "13/13",
|
|
258
|
+
"implemented": [
|
|
259
|
+
"createUser",
|
|
260
|
+
"setProfile",
|
|
261
|
+
"refreshSession",
|
|
262
|
+
"reportLocation",
|
|
263
|
+
"post",
|
|
264
|
+
"recentPostsByOthers",
|
|
265
|
+
"like",
|
|
266
|
+
"comment",
|
|
267
|
+
"openConversation",
|
|
268
|
+
"sendMessage",
|
|
269
|
+
"listGroups",
|
|
270
|
+
"joinGroup",
|
|
271
|
+
"deleteUser"
|
|
272
|
+
],
|
|
273
|
+
"notTested": []
|
|
274
|
+
},
|
|
275
|
+
"cleanup": {
|
|
276
|
+
"removed": 6,
|
|
277
|
+
"notDeleted": [],
|
|
278
|
+
"failed": []
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* real backend, and that backend was ours — a testing tool that has only tested
|
|
7
7
|
* its author's own app has not been shown to be portable.
|
|
8
8
|
*
|
|
9
|
-
* So every architectural choice here disagrees with Buzz
|
|
9
|
+
* So every architectural choice here disagrees with Buzz on purpose:
|
|
10
10
|
*
|
|
11
|
-
* Buzz
|
|
11
|
+
* Buzz / Supabase this server
|
|
12
12
|
* ──────────────────── ───────────────────────────────
|
|
13
13
|
* supabase-js client plain fetch over HTTP
|
|
14
14
|
* UUID string ids INTEGER ids
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* RLS refuses in the database the handler refuses in application code
|
|
19
19
|
*
|
|
20
20
|
* The bare id arrays matter most: that shape is what caught the engine reading
|
|
21
|
-
* `target.id` off a string. If this file agreed with Buzz
|
|
21
|
+
* `target.id` off a string. If this file agreed with Buzz it would prove
|
|
22
22
|
* nothing.
|
|
23
23
|
*
|
|
24
24
|
* Zero dependencies, in-memory, and it binds to 127.0.0.1 only — it is a test
|
|
@@ -196,7 +196,7 @@ const routes = {
|
|
|
196
196
|
const thread = db.threads.find((t) => t.id === Number(body.threadId));
|
|
197
197
|
if (!thread) return [404, { error: "no such thread" }];
|
|
198
198
|
// Refused in application code rather than by a database policy — a
|
|
199
|
-
// different enforcement point from Buzz
|
|
199
|
+
// different enforcement point from Buzz, deliberately.
|
|
200
200
|
if (thread.a !== auth.user.id && thread.b !== auth.user.id) {
|
|
201
201
|
return [403, { error: "not a participant in this thread" }];
|
|
202
202
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gigzen/populace",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A simulated population that uses your app through its real API, so you can test what needs more than one person.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"examples",
|
|
18
18
|
"populace.config.example.mjs",
|
|
19
19
|
"README.md",
|
|
20
|
-
"LICENSE"
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"action.yml"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"demo": "node src/cli.mjs demo",
|