`npm test` did nothing until now. CI that runs no tests is theatre, so the tests came first — 39 of them, over the two places where an error would be silent and expensive. packages/core: the margin arithmetic. Every dashboard figure, idle-capacity alert and agent answer resolves through it, and wrong numbers still look like numbers. The cases pin decisions rather than implementation: cost is charged against the full commitment (a naive version reports the opposite sign on a loss-making block), aggregation sums cents rather than averaging percentages (averaging reports +22% on a book that is losing money), break-even prices the remaining hours and returns null rather than Infinity when there are none, and internal research burn counts as cost with no revenue. packages/prime: the upstream mapping. Rounding rather than truncating cents, because 2.43 is 2.4299999 in binary and a lost cent compounds across millions of GPU-hours. And interconnect normalisation, where an unrecognised fabric maps to Unknown rather than Ethernet — guessing low loses a deal, guessing high sells a training customer a cluster that cannot train. CI runs on push and pull request: typecheck all six packages, unit tests, migrations applied twice to a real Postgres, a seed-idempotency assertion that fails the build if row counts move on a second run, a server boot, the front-end build, and a Docker build. It also asserts the inline theme script's hash still matches the CSP the proxy allows. That script prevents a white flash for dark-mode users; if it changes without the CSP being updated, the browser silently blocks it and nothing anywhere reports an error. Deployment stays a script rather than push-to-deploy. Automating it would put an SSH key with production write access on the CI runner — a real escalation for a project this size. The script takes a database dump before migrating and refuses to finish if an unauthenticated request returns anything but 401. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Tests for the upstream-to-PIG mapping.
|
||||
*
|
||||
* Two things here are worth defending with tests, because getting either wrong
|
||||
* is expensive and neither would throw:
|
||||
*
|
||||
* **Money.** Upstream sends floating-point dollars; PIG stores integer
|
||||
* cents. Truncating instead of rounding loses a cent on values that cannot
|
||||
* be represented exactly in binary, and a cent compounds across millions of
|
||||
* GPU-hours.
|
||||
*
|
||||
* **Interconnect.** The field that decides whether capacity can train or
|
||||
* only serve. Guessing wrong in either direction loses a deal or sells a
|
||||
* customer a cluster that cannot do the job.
|
||||
*/
|
||||
import { strict as assert } from 'node:assert';
|
||||
import { describe, it } from 'node:test';
|
||||
import { mapListing, toCents } from '../src/map';
|
||||
import type { PrimeGpuListing } from '../src/client';
|
||||
|
||||
const listing = (over: Partial<PrimeGpuListing> = {}): PrimeGpuListing => ({
|
||||
gpuType: 'H100_80GB',
|
||||
gpuCount: 8,
|
||||
raw: {},
|
||||
...over,
|
||||
});
|
||||
|
||||
describe('toCents', () => {
|
||||
it('rounds rather than truncating', () => {
|
||||
// 2.43 is 2.4299999... in binary. Truncating gives 242 and loses a cent
|
||||
// on every single listing.
|
||||
assert.equal(toCents(2.43), 243);
|
||||
assert.equal(toCents(0.47), 47);
|
||||
assert.equal(toCents(12.005), 1201);
|
||||
});
|
||||
|
||||
it('passes through null and rejects nonsense', () => {
|
||||
assert.equal(toCents(null), null);
|
||||
assert.equal(toCents(undefined), null);
|
||||
assert.equal(toCents(Number.NaN), null);
|
||||
assert.equal(toCents(Number.POSITIVE_INFINITY), null);
|
||||
});
|
||||
|
||||
it('handles zero, which is a real price and not a missing one', () => {
|
||||
assert.equal(toCents(0), 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapListing — interconnect', () => {
|
||||
const cases: [string, string][] = [
|
||||
['Infiniband', 'Infiniband'],
|
||||
['InfiniBand', 'Infiniband'],
|
||||
['INFINIBAND', 'Infiniband'],
|
||||
['infini_band', 'Infiniband'],
|
||||
['IB', 'Infiniband'],
|
||||
['RoCE', 'RoCE'],
|
||||
['roce v2', 'RoCE'],
|
||||
['NVLink', 'NVLink'],
|
||||
['nvl', 'NVLink'],
|
||||
['Ethernet', 'Ethernet'],
|
||||
['eth', 'Ethernet'],
|
||||
];
|
||||
|
||||
for (const [input, expected] of cases) {
|
||||
it(`normalises "${input}" to ${expected}`, () => {
|
||||
assert.equal(mapListing(listing({ interconnectType: input }))!.interconnectType, expected);
|
||||
});
|
||||
}
|
||||
|
||||
it('maps an unrecognised fabric to Unknown, never to Ethernet', () => {
|
||||
// Assuming Ethernet would understate real capacity; assuming InfiniBand
|
||||
// would sell a training customer a cluster that cannot train. Neither
|
||||
// error is acceptable, so it stays explicitly unknown.
|
||||
assert.equal(mapListing(listing({ interconnectType: 'Omni-Path' }))!.interconnectType, 'Unknown');
|
||||
assert.equal(mapListing(listing({ interconnectType: '' }))!.interconnectType, 'Unknown');
|
||||
assert.equal(mapListing(listing({ interconnectType: undefined }))!.interconnectType, 'Unknown');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapListing — stock', () => {
|
||||
it('treats an unrecognised stock signal as Unavailable', () => {
|
||||
// Under-promising inventory is recoverable. A seller offering capacity
|
||||
// that turns out not to exist is not.
|
||||
assert.equal(mapListing(listing({ stockStatus: 'wat' }))!.stockStatus, 'Unavailable');
|
||||
assert.equal(mapListing(listing({ stockStatus: undefined }))!.stockStatus, 'Unavailable');
|
||||
});
|
||||
|
||||
it('passes known values through, case-insensitively', () => {
|
||||
assert.equal(mapListing(listing({ stockStatus: 'available' }))!.stockStatus, 'Available');
|
||||
assert.equal(mapListing(listing({ stockStatus: 'HIGH' }))!.stockStatus, 'High');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapListing — general', () => {
|
||||
it('drops a listing with no GPU type or count — there is nothing sellable', () => {
|
||||
assert.equal(mapListing(listing({ gpuType: undefined })), null);
|
||||
assert.equal(mapListing(listing({ gpuCount: undefined })), null);
|
||||
assert.equal(mapListing(listing({ gpuCount: 0 })), null);
|
||||
});
|
||||
|
||||
it('converts prices to integer cents', () => {
|
||||
const m = mapListing(listing({ prices: { onDemand: 2.43, communityPrice: 0.94 } }))!;
|
||||
assert.equal(m.onDemandPriceCents, 243);
|
||||
assert.equal(m.communityPriceCents, 94);
|
||||
});
|
||||
|
||||
it('defaults to the secure tier unless community is stated', () => {
|
||||
// Mislabelling community capacity as secure would let it be sold against a
|
||||
// requirement it cannot meet.
|
||||
assert.equal(mapListing(listing({}))!.securityTier, 'secure_cloud');
|
||||
assert.equal(
|
||||
mapListing(listing({ security: 'community_cloud' }))!.securityTier,
|
||||
'community_cloud',
|
||||
);
|
||||
});
|
||||
|
||||
it('normalises sockets and drops unknown ones rather than inventing a value', () => {
|
||||
assert.equal(mapListing(listing({ socket: 'sxm5' }))!.socket, 'SXM5');
|
||||
assert.equal(mapListing(listing({ socket: 'pcie' }))!.socket, 'PCIe');
|
||||
assert.equal(mapListing(listing({ socket: 'SXM_5' }))!.socket, 'SXM5');
|
||||
// The column is an enum; an unmapped value would fail the insert.
|
||||
assert.equal(mapListing(listing({ socket: 'weird' }))!.socket, null);
|
||||
});
|
||||
|
||||
it('unwraps counts sent as objects', () => {
|
||||
const m = mapListing(listing({ vcpu: { defaultCount: 96 }, memory: 1024 }))!;
|
||||
assert.equal(m.vcpu, 96);
|
||||
assert.equal(m.memoryGb, 1024);
|
||||
});
|
||||
|
||||
it('preserves the raw payload so a new upstream field is not lost', () => {
|
||||
const raw = { gpuType: 'H100_80GB', gpuCount: 8, somethingNew: 'value' };
|
||||
const m = mapListing({ ...listing(), raw })!;
|
||||
assert.equal((m.raw as Record<string, unknown>).somethingNew, 'value');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user