mirror of https://github.com/garrytan/gstack.git
51 lines
2.0 KiB
TypeScript
51 lines
2.0 KiB
TypeScript
/**
|
|
* Budget override audit trail (v1.45.0.0 T5).
|
|
*
|
|
* Records uses of GSTACK_SIZE_BUDGET_OVERRIDE_REASON or
|
|
* EVALS_BUDGET_OVERRIDE_REASON so a reviewer can see what was waived,
|
|
* by whom, and why. Append-only JSONL at ~/.gstack/analytics/spend-overrides.jsonl.
|
|
*
|
|
* Why audit: a hard cap with no escape valve becomes operationally hostile
|
|
* (legit price changes, longer transcripts, new required evals can all
|
|
* blow the cap). An escape valve with no audit becomes "everyone overrides
|
|
* everything and we lose the gate." This module is the audit half.
|
|
*/
|
|
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as os from 'os';
|
|
|
|
export interface BudgetOverrideEntry {
|
|
scope: string; // e.g. 'skill-size-budget', 'evals-cost-cap'
|
|
reason: string; // user-supplied REASON env var
|
|
details?: Record<string, unknown>; // numbers / regressions
|
|
}
|
|
|
|
function getAuditPath(): string {
|
|
const base = process.env.GSTACK_HOME || path.join(os.homedir(), '.gstack');
|
|
return path.join(base, 'analytics', 'spend-overrides.jsonl');
|
|
}
|
|
|
|
export function logBudgetOverride(entry: BudgetOverrideEntry): void {
|
|
try {
|
|
const auditPath = getAuditPath();
|
|
fs.mkdirSync(path.dirname(auditPath), { recursive: true });
|
|
const line = JSON.stringify({
|
|
timestamp: new Date().toISOString(),
|
|
scope: entry.scope,
|
|
reason: entry.reason,
|
|
details: entry.details ?? {},
|
|
// Capture provenance: who/where/which CI ran
|
|
ci: process.env.CI === 'true',
|
|
runner: process.env.GITHUB_ACTIONS ? 'github-actions' : process.env.CI_RUNNER || 'local',
|
|
branch: process.env.GITHUB_REF_NAME || process.env.CI_COMMIT_REF_NAME || 'unknown',
|
|
commit: process.env.GITHUB_SHA?.slice(0, 8) || process.env.CI_COMMIT_SHORT_SHA || 'unknown',
|
|
}) + '\n';
|
|
fs.appendFileSync(auditPath, line);
|
|
} catch (err) {
|
|
// Best-effort logging; don't fail the test on audit-write errors.
|
|
// eslint-disable-next-line no-console
|
|
console.warn(`[budget-override] could not write audit log: ${(err as Error).message}`);
|
|
}
|
|
}
|