sparta_worlds 0.6.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.
Files changed (93) hide show
  1. package/LICENSE.txt +15 -0
  2. package/bin/worlds.js +53 -0
  3. package/dist/cli/argv.js +27 -0
  4. package/dist/cli/claims.js +250 -0
  5. package/dist/cli/commands.js +67 -0
  6. package/dist/cli/contract.js +142 -0
  7. package/dist/cli/demo.js +114 -0
  8. package/dist/cli/doctor.js +299 -0
  9. package/dist/cli/expect.js +197 -0
  10. package/dist/cli/home.js +18 -0
  11. package/dist/cli/import.js +530 -0
  12. package/dist/cli/index.js +1014 -0
  13. package/dist/cli/init.js +725 -0
  14. package/dist/cli/judge-command.js +184 -0
  15. package/dist/cli/judge.js +1495 -0
  16. package/dist/cli/load.js +8 -0
  17. package/dist/cli/packs.js +82 -0
  18. package/dist/cli/passk.js +1256 -0
  19. package/dist/cli/policy-starters.js +83 -0
  20. package/dist/cli/preload.js +45 -0
  21. package/dist/cli/report.js +579 -0
  22. package/dist/cli/rubric.js +727 -0
  23. package/dist/cli/run.js +266 -0
  24. package/dist/cli/scoreboard.js +432 -0
  25. package/dist/cli/selftest.js +157 -0
  26. package/dist/cli/stdio.js +25 -0
  27. package/dist/cli/tasks.js +1246 -0
  28. package/dist/cli/try.js +156 -0
  29. package/dist/cli/version.js +17 -0
  30. package/package.json +38 -0
  31. package/packs/cancellations.yaml +201 -0
  32. package/packs/credits.yaml +274 -0
  33. package/packs/invoices.yaml +206 -0
  34. package/packs/plan-changes.yaml +170 -0
  35. package/packs/refunds.yaml +437 -0
  36. package/preload/node-hooks.mjs +28 -0
  37. package/preload/node.mjs +19 -0
  38. package/preload/python/sitecustomize.py +88 -0
  39. package/preload/wrap.mjs +81 -0
  40. package/rubrics/acme-prod-library.json +1427 -0
  41. package/rubrics/acme-prod-shift.json +499 -0
  42. package/server/dist/admin/auth.js +145 -0
  43. package/server/dist/admin/routes.js +469 -0
  44. package/server/dist/admin/schemas.js +243 -0
  45. package/server/dist/app.js +112 -0
  46. package/server/dist/core/canonical.js +22 -0
  47. package/server/dist/core/db.js +294 -0
  48. package/server/dist/core/errors.js +136 -0
  49. package/server/dist/core/manager.js +337 -0
  50. package/server/dist/core/money.js +43 -0
  51. package/server/dist/core/nondeterministic.js +39 -0
  52. package/server/dist/core/paths.js +33 -0
  53. package/server/dist/core/prng.js +19 -0
  54. package/server/dist/core/protocol.js +1 -0
  55. package/server/dist/core/publicUrl.js +49 -0
  56. package/server/dist/core/seed.js +286 -0
  57. package/server/dist/core/seedExport.js +169 -0
  58. package/server/dist/core/seedLoader.js +156 -0
  59. package/server/dist/core/time.js +45 -0
  60. package/server/dist/core/world.js +361 -0
  61. package/server/dist/index.js +17 -0
  62. package/server/dist/main.js +42 -0
  63. package/server/dist/scenario/engine.js +172 -0
  64. package/server/dist/scenario/library.js +49 -0
  65. package/server/dist/twin/build.js +372 -0
  66. package/server/dist/twin/pagination.js +32 -0
  67. package/server/dist/twin/params.js +118 -0
  68. package/server/dist/twin/resources/charges.js +24 -0
  69. package/server/dist/twin/resources/customers.js +151 -0
  70. package/server/dist/twin/resources/events.js +26 -0
  71. package/server/dist/twin/resources/invoices.js +217 -0
  72. package/server/dist/twin/resources/payment_intents.js +146 -0
  73. package/server/dist/twin/resources/products.js +92 -0
  74. package/server/dist/twin/resources/refunds.js +103 -0
  75. package/server/dist/twin/resources/shared.js +113 -0
  76. package/server/dist/twin/resources/subscriptions.js +325 -0
  77. package/server/dist/twin/resources/tickets.js +128 -0
  78. package/server/dist/twin/router.js +279 -0
  79. package/server/dist/twin/unsupported.js +212 -0
  80. package/server/dist/webhooks/dispatcher.js +148 -0
  81. package/server/scenarios/auth-expiry.yaml +7 -0
  82. package/server/scenarios/intermittent-500s.yaml +9 -0
  83. package/server/scenarios/lock-timeouts.yaml +12 -0
  84. package/server/scenarios/rate-limit-storm.yaml +10 -0
  85. package/server/scenarios/slow-stripe.yaml +9 -0
  86. package/server/scenarios/stripe-storm-shift.yaml +15 -0
  87. package/server/scenarios/tickets-storm.yaml +10 -0
  88. package/server/scenarios/webhook-chaos.yaml +7 -0
  89. package/server/seeds/acme-prod-library.json +40470 -0
  90. package/server/seeds/acme-prod-shift.json +36544 -0
  91. package/server/seeds/acme-prod.json +35412 -0
  92. package/server/seeds/saas-billing-small.json +4792 -0
  93. package/server/seeds/saas-billing-smoke.json +160 -0
@@ -0,0 +1,184 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { chargeLookupFor, judgeShift, judgeWorld, parseTranscriptLines, planTranscriptJudge, policyAmountsCents, summarizeJudge, } from "./judge.js";
4
+ import { createAdminCall, judgeLines, judgeSummaryLine, PasskConfigError, requireBeforeImages, resolveJudge, } from "./passk.js";
5
+ import { gradeShift, loadRubric } from "./rubric.js";
6
+ import { stdioDead } from "./stdio.js";
7
+ export async function runJudgeCommand(opts) {
8
+ let rubric;
9
+ try {
10
+ rubric = opts.rubric ? loadRubric(opts.rubric) : undefined;
11
+ }
12
+ catch (err) {
13
+ throw new PasskConfigError(err instanceof Error ? err.message : String(err), { cause: err });
14
+ }
15
+ const judge = await resolveJudge({
16
+ policyFile: opts.policyFile,
17
+ policyText: opts.policyText,
18
+ model: opts.model,
19
+ runs: opts.runs,
20
+ budget: opts.budget,
21
+ client: opts.client,
22
+ });
23
+ const log = opts.log ??
24
+ ((line) => {
25
+ if (!stdioDead(process.stderr))
26
+ console.error(line);
27
+ });
28
+ const admin = opts.admin ?? createAdminCall(opts.adminUrl, opts.adminToken);
29
+ const { worldId, mark } = opts;
30
+ const diff = await admin("GET", `/admin/worlds/${worldId}/diff?from=${encodeURIComponent(mark)}`);
31
+ requireBeforeImages(diff);
32
+ const shift = rubric
33
+ ? await gradeShift(rubric, diff, chargeLookupFor(admin, worldId))
34
+ : undefined;
35
+ const evidenceDir = opts.evidence ? join(resolve(opts.evidence), worldId, "judge") : undefined;
36
+ log(`judge: world ${worldId} since mark ${mark} · ${judge.model}${judge.runs > 1 ? ` × ${judge.runs}` : ""}${rubric ? ` · against rubric ${rubric.name}` : ""}`);
37
+ const result = await judgeWorld({
38
+ admin,
39
+ worldId,
40
+ diff,
41
+ policy: judge.policy,
42
+ model: judge.model,
43
+ runs: judge.runs,
44
+ client: judge.client,
45
+ budget: judge.budget ?? rubric?.budget?.credits_total_max ?? null,
46
+ evidenceDir,
47
+ log,
48
+ });
49
+ const summary = summarizeJudge([result], shift ? [shift] : undefined);
50
+ const payload = {
51
+ world_id: worldId,
52
+ mark,
53
+ judge: result,
54
+ summary,
55
+ judge_config: {
56
+ model: judge.model,
57
+ runs: judge.runs,
58
+ policy_sha256: judge.policy_sha256,
59
+ ...(opts.policyFile ? { policy_file: resolve(opts.policyFile) } : {}),
60
+ },
61
+ ...(shift ? { shift } : {}),
62
+ };
63
+ if (opts.jsonFile) {
64
+ const file = resolve(opts.jsonFile);
65
+ mkdirSync(dirname(file), { recursive: true });
66
+ writeFileSync(file, `${JSON.stringify(payload, null, 2)}\n`);
67
+ }
68
+ if (opts.json) {
69
+ console.log(JSON.stringify(payload, null, 2));
70
+ }
71
+ else {
72
+ console.log("");
73
+ for (const line of judgeLines(result))
74
+ console.log(line);
75
+ console.log("");
76
+ console.log(judgeSummaryLine(judge.model, summary));
77
+ if (evidenceDir)
78
+ console.log(`evidence: ${evidenceDir}`);
79
+ }
80
+ return 0;
81
+ }
82
+ export async function runTranscriptJudgeCommand(opts) {
83
+ const judge = await resolveJudge({
84
+ policyFile: opts.policyFile,
85
+ policyText: opts.policyText,
86
+ model: opts.model,
87
+ runs: opts.runs,
88
+ budget: opts.budget,
89
+ client: opts.client,
90
+ });
91
+ let clockAtMark = null;
92
+ if (opts.clock !== undefined) {
93
+ const ms = Date.parse(opts.clock);
94
+ if (!Number.isFinite(ms))
95
+ throw new PasskConfigError(`--clock must be an ISO timestamp (got '${opts.clock}')`);
96
+ clockAtMark = Math.floor(ms / 1000);
97
+ }
98
+ const file = resolve(opts.transcript);
99
+ let records;
100
+ try {
101
+ records = parseTranscriptLines(readFileSync(file, "utf8"));
102
+ }
103
+ catch (err) {
104
+ throw new PasskConfigError(`--transcript ${file}: ${err instanceof Error ? err.message : String(err)}`, {
105
+ cause: err,
106
+ });
107
+ }
108
+ if (records.length === 0)
109
+ throw new PasskConfigError(`--transcript ${file}: no records`);
110
+ const log = opts.log ??
111
+ ((line) => {
112
+ if (!stdioDead(process.stderr))
113
+ console.error(line);
114
+ });
115
+ const byWorld = new Map();
116
+ for (const r of records) {
117
+ const list = byWorld.get(r.world_id) ?? [];
118
+ list.push(r);
119
+ byWorld.set(r.world_id, list);
120
+ }
121
+ log(`judge: transcript ${file} · ${records.length} ticket(s) in ${byWorld.size} world(s) · ${judge.model}${judge.runs > 1 ? ` × ${judge.runs}` : ""}`);
122
+ const worlds = [];
123
+ for (const [worldId, list] of byWorld) {
124
+ const plan = planTranscriptJudge(list, {
125
+ clockAtMark,
126
+ budget: judge.budget ?? null,
127
+ policyAmounts: policyAmountsCents(judge.policy),
128
+ });
129
+ const evidenceDir = opts.evidence
130
+ ? join(resolve(opts.evidence), worldId ?? "no-world", "transcript-judge")
131
+ : undefined;
132
+ if (evidenceDir)
133
+ mkdirSync(evidenceDir, { recursive: true });
134
+ log(` ⚖ judge (${judge.model}${judge.runs > 1 ? ` × ${judge.runs}` : ""}, transcript): ${plan.tickets.length} tickets${worldId ? ` · world ${worldId}` : ""}`);
135
+ const result = await judgeShift(plan, judge.policy, {
136
+ model: judge.model,
137
+ client: judge.client,
138
+ samples: judge.runs,
139
+ log,
140
+ ...(evidenceDir
141
+ ? {
142
+ onTicket: (input, raw, verdict) => writeFileSync(join(evidenceDir, `${verdict.ticket_id}.json`), `${JSON.stringify({ input, raw, verdict }, null, 2)}\n`),
143
+ }
144
+ : {}),
145
+ });
146
+ worlds.push({ world_id: worldId, tickets: list.length, judge: result });
147
+ }
148
+ const summary = summarizeJudge(worlds.map((w) => w.judge));
149
+ const payload = {
150
+ transcript: file,
151
+ clock_at_mark_iso: clockAtMark === null ? null : new Date(clockAtMark * 1000).toISOString().replace(/\.\d{3}Z$/, "Z"),
152
+ worlds,
153
+ summary,
154
+ judge_config: {
155
+ model: judge.model,
156
+ runs: judge.runs,
157
+ policy_sha256: judge.policy_sha256,
158
+ ...(opts.policyFile ? { policy_file: resolve(opts.policyFile) } : {}),
159
+ evidence: "transcript",
160
+ },
161
+ };
162
+ if (opts.jsonFile) {
163
+ const out = resolve(opts.jsonFile);
164
+ mkdirSync(dirname(out), { recursive: true });
165
+ writeFileSync(out, `${JSON.stringify(payload, null, 2)}\n`);
166
+ }
167
+ if (opts.json) {
168
+ console.log(JSON.stringify(payload, null, 2));
169
+ }
170
+ else {
171
+ for (const w of worlds) {
172
+ console.log("");
173
+ if (worlds.length > 1)
174
+ console.log(`world ${w.world_id ?? "(none)"}:`);
175
+ for (const line of judgeLines(w.judge))
176
+ console.log(line);
177
+ }
178
+ console.log("");
179
+ console.log(judgeSummaryLine(judge.model, summary));
180
+ if (opts.evidence)
181
+ console.log(`evidence: ${resolve(opts.evidence)}`);
182
+ }
183
+ return 0;
184
+ }