/** * That the ledger is not a keyhole into somebody's chat history. * * The two files were contradicting each other. `piggy-conversations.ts` states * that a transcript belongs to exactly one person and that a platform admin is * deliberately not an exception, because the audit trail lives in `agent_runs`. * `PiggyActivityService` agrees in its header — and then widens `agent_runs` to * the whole workspace for an admin while returning `label`, which is the user's * question, and `summary`, which is the first line of Piggy's answer. Both of * those are the transcript by another name. * * It is settled the way the conversation store settles it: cost and outcome are * the company's record, the words are the person's. These assertions are what * keep the two files agreeing. */ import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import test from 'node:test'; import { PIGGY_WITHHELD_LABEL, withoutOtherPeoplesWords, } from '../src/routes/piggy-activity'; import type { PiggyActivityOverview, PiggyRunSummary, } from '../src/services/piggy-activity'; function run(overrides: Partial = {}): PiggyRunSummary { return { id: '40000000-0000-4000-8000-000000000001', kind: 'chat', agent: 'piggy', status: 'succeeded', model: 'nvidia/nemotron-3-nano-30b-a3b', label: 'Are we under water on the Northwind renewal?', summary: 'Yes — the block is 38 per cent idle at the current rate.', error: null, inputTokens: 2_100, outputTokens: 180, costMicroCents: 4_200, startedAt: '2026-08-13T09:00:00.000Z', finishedAt: '2026-08-13T09:00:04.000Z', durationMs: 4_000, taskKind: null, conversation: null, /** * Populated ONLY when the run is somebody else's — that is what the service * promises, and it is the signal the redaction turns on. */ principal: { id: '50000000-0000-4000-8000-00000000000b', name: 'A colleague' }, ...overrides, }; } function overview(runs: PiggyRunSummary[]): PiggyActivityOverview { return { runs, tasks: [], spend: { todayMicroCents: 4_200, monthMicroCents: 91_000, turns: 22 }, }; } test('an administrator reads a colleague’s spend and not their question', () => { const [redacted] = withoutOtherPeoplesWords(overview([run()])).runs; assert.ok(redacted); // The words, which are the half that belongs to the person who typed them. assert.equal(redacted.label, PIGGY_WITHHELD_LABEL); assert.equal(redacted.summary, null); // Everything an audit is actually for, which is the half that belongs to PIG. assert.equal(redacted.status, 'succeeded'); assert.equal(redacted.model, 'nvidia/nemotron-3-nano-30b-a3b'); assert.equal(redacted.costMicroCents, 4_200); assert.equal(redacted.inputTokens, 2_100); assert.equal(redacted.durationMs, 4_000); assert.equal(redacted.principal?.name, 'A colleague'); }); test('a failure stays legible, because that is what an admin is looking for', () => { const failed = run({ status: 'failed', error: 'Prime Inference returned 429.' }); const [redacted] = withoutOtherPeoplesWords(overview([failed])).runs; assert.equal(redacted?.error, 'Prime Inference returned 429.'); assert.equal(redacted?.status, 'failed'); assert.equal(redacted?.label, PIGGY_WITHHELD_LABEL); }); test('my own rows are untouched, whoever I am', () => { // The service leaves `principal` null on the caller's own runs, so this is // the shape an ordinary member sees for every row and an admin sees for // theirs. Redacting it would take somebody's history away from themselves. const mine = run({ principal: null }); const [kept] = withoutOtherPeoplesWords(overview([mine])).runs; assert.deepEqual(kept, mine); }); test('the spend and the queue are not touched', () => { const before = overview([run(), run({ principal: null })]); const after = withoutOtherPeoplesWords(before); assert.deepEqual(after.spend, before.spend); assert.deepEqual(after.tasks, before.tasks); assert.equal(after.runs.length, 2); }); /** * The gate is one call, and a route that stops making it looks exactly like a * route that still does. Asserted against the source for the same reason * read-governance.test.ts reads route files: there is nothing else to catch a * deletion here. */ test('the route still applies the gate', () => { const source = readFileSync( join(import.meta.dirname, '..', 'src', 'routes', 'piggy-activity.ts'), 'utf8', ); assert.match(source, /withoutOtherPeoplesWords\(await activity\.overview\(/); });