Files

46 lines
3.3 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { decisionAutonomy } from '../src/rails.mjs';
import { VERB_RIGHTS } from '../src/org-rights.mjs';
test('AU absent key preserves fixed levels; present per-class levels are read', () => {
for (const name of ['merge', 'policy', 'cross-role']) assert.equal(decisionAutonomy(name), 'out of the loop');
assert.equal(decisionAutonomy('authority'), 'in the loop');
assert.equal(decisionAutonomy('merge', { merge: 'near the loop' }), 'near the loop');
});
test('AU unknown class or level refuses instead of inventing a default', () => {
assert.throws(() => decisionAutonomy('unknown'), { code: 'invalid-autonomy' });
assert.throws(() => decisionAutonomy('merge', { merge: 'automatic' }), { code: 'invalid-autonomy' });
});
test('AU owner-only Console verbs have explicit null rights', () => {
for (const verb of ['autonomy.get.console','autonomy.set.console','decision.confirm.console','decision.reverse.console']) assert.equal(VERB_RIGHTS[verb], null, verb);
});
import { tmp, rolesCopy, businessDoc, writeJson } from './helpers.mjs';
import { rmSync } from 'node:fs';
import { join } from 'node:path';
import { validateBusinessDocument } from '../src/organization-config.mjs';
import { organizationWriter } from '../src/organization.mjs';
test('AU setting validates in the organization file; every writer refuses non-owner edits',t=>{
const root=tmp();t.after(()=>rmSync(root,{recursive:true,force:true}));
const rolesDir=rolesCopy(root),doc=businessDoc(root);doc.autonomy={merge:'in the loop'};
assert.equal(validateBusinessDocument(doc,join(root,'acme.json'),{rolesDir}).autonomy.merge,'in the loop');
for(const autonomy of [{unknown:'in the loop'},{merge:'fast'},{deploy:'out of the loop'}])assert.throws(()=>validateBusinessDocument({...doc,autonomy},join(root,'acme.json'),{rolesDir}),{code:'invalid-autonomy'});
writeJson(join(root,'businesses/acme.json'),doc);
const writer=organizationWriter({dir:root,rolesDir}),old=writer.read('acme');
for(const actor of ['coder','tester','member'])assert.throws(()=>writer.write('acme',{...doc,autonomy:{merge:'out of the loop'}},{revision:old.revision,actor}),{code:'human-required'});
});
import {authorityBudgetCovered} from '../src/autonomy.mjs';
test('AU authority budgets cover all selectable models and only enforced account harnesses',()=>{
const cap={limit:0,since:'2026-01-01T00:00:00.000Z'};
const b={plugins:{harness:['pi'],'limit-check':['token-limit']},launch:{models:{one:{provider:'one',model:'m'},two:{provider:'two',model:'n'}},limits:{tokens:{providers:{one:cap}}}}};
assert.equal(authorityBudgetCovered(b),false);
b.launch.limits.tokens.models={two:{n:cap}};assert.equal(authorityBudgetCovered(b),true);
b.plugins['limit-check']=[];assert.equal(authorityBudgetCovered(b),false);
b.launch.account={name:'shared'};b.launch.limits.tokens={keys:{shared:cap}};b.plugins['limit-check']=['token-limit'];
assert.equal(authorityBudgetCovered(b),false);
b.plugins.harness=['claude-code'];assert.equal(authorityBudgetCovered(b),true);
b.plugins.harness.push('pi');assert.equal(authorityBudgetCovered(b),false);
b.plugins.harness=['claude-code'];b.plugins['limit-check']=['daily-quota'];b.launch.limits.tokens={daily:{shared:{...cap,reset:'00:00',timeZone:'UTC'}}};assert.equal(authorityBudgetCovered(b),true);
});