feat(config): register spend-control keys + validate spend.posture (#2139)

Adds spend.posture + the five previously --force-only spend knobs to
KNOWN_CONFIG_KEYS so `config set` accepts them directly (removes the
archaeology the issue complained about), and rejects invalid spend.posture
values at set time with a paste-ready hint.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-06-14 11:43:03 -07:00
co-authored by Claude Opus 4.8
parent dfb4e5ca69
commit 1bb3b7a7fb
2 changed files with 23 additions and 0 deletions
+14
View File
@@ -181,6 +181,20 @@ export async function runConfig(engine: BrainEngine, args: string[]) {
const coverageOverride =
args.includes('--coverage-override') || args.includes('--yes');
// v0.42.42.0 (#2139): validate spend.posture at set time so a typo
// ('tokenMax', 'max') doesn't silently fall back to gated.
if (key === 'spend.posture') {
const { isValidSpendPosture } = await import('../core/spend-posture.ts');
if (!isValidSpendPosture(value)) {
console.error(
`[config] spend.posture must be 'gated' or 'tokenmax' (got '${value}').\n` +
`[config] gbrain config set spend.posture tokenmax # cost gates become informational\n` +
`[config] gbrain config set spend.posture gated # default — gates enforce`,
);
process.exit(1);
}
}
if (key === 'embedding_columns') {
try {
const parsed = JSON.parse(value);
+9
View File
@@ -892,6 +892,15 @@ export const KNOWN_CONFIG_KEYS: readonly string[] = [
// Link resolution (issue #972)
'link_resolution',
'link_resolution.global_basename',
// Spend controls (v0.42.42.0, issue #2139). Previously `--force`-only — the
// operator had to discover these by reading source. Registered so `config
// set` accepts them directly. See docs/operations/spend-controls.md.
'spend.posture',
'sync.cost_gate_min_usd',
'sync.federated_v2',
'embed.backfill_cooldown_min',
'embed.backfill_max_usd_per_source_24h',
'embed.backfill_max_usd',
];
/**