46 lines
3.3 KiB
JavaScript
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);
|
|
});
|