model-runtime-lane-data-integrity.test.mjs
142 lines 5.7 KB
Raw
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 22 hours ago
1 /**
2 * Tier 5 — DATA INTEGRITY: model-runtime-lane correctness and state properties
3 *
4 * Verifies:
5 * - selectLane is deterministic: identical inputs always produce identical outputs.
6 * - enforceConsentPolicy is deterministic across repeated calls.
7 * - Input objects are never mutated (functions are pure — no side effects).
8 * - All returned lane values are members of the canonical RUNTIME_LANES set.
9 * - Partial / sparse capability objects are handled safely (missing fields = false).
10 * - Null / undefined field values in capabilities/preferences do not throw.
11 *
12 * Reference: docs/COMPANION-APP-PHASE-1-ADAPTER-SEAM.md §5 (pure function invariants)
13 */
14 import { describe, it } from 'node:test';
15 import assert from 'node:assert/strict';
16 import {
17 selectLane,
18 isManagedLane,
19 enforceConsentPolicy,
20 RUNTIME_LANES,
21 } from '../lib/model-runtime-lane.mjs';
22
23 const VALID_LANES = new Set(RUNTIME_LANES);
24
25 describe('Data integrity — selectLane determinism', () => {
26 const fixtureCases = [
27 [{ inBrowserAvailable: true }, {}, 'local'],
28 [{ companionAvailable: true }, {}, 'local'],
29 [{ managedKeyAvailable: true }, {}, 'direct_provider'],
30 [{ openrouterKeyAvailable: true }, {}, 'openrouter'],
31 [{}, {}, 'disabled'],
32 [{ selfHostedAvailable: true }, { orgPrivacyMode: true }, 'self_hosted'],
33 [{ managedKeyAvailable: true }, { orgPrivacyMode: true }, 'disabled'],
34 ];
35
36 for (const [caps, prefs, expected] of fixtureCases) {
37 it(`caps=${JSON.stringify(caps)}, prefs=${JSON.stringify(prefs)} → always '${expected}'`, () => {
38 for (let i = 0; i < 100; i++) {
39 assert.equal(selectLane(caps, prefs), expected);
40 }
41 });
42 }
43 });
44
45 describe('Data integrity — all returned lanes are in RUNTIME_LANES', () => {
46 it('exhaustive permutation: all results are valid lane values', () => {
47 const boolPairs = [true, false];
48 for (const inBrowser of boolPairs)
49 for (const companion of boolPairs)
50 for (const selfHosted of boolPairs)
51 for (const enterprise of boolPairs)
52 for (const openrouter of boolPairs)
53 for (const managed of boolPairs)
54 for (const orgPrivacy of boolPairs) {
55 const lane = selectLane(
56 {
57 inBrowserAvailable: inBrowser,
58 companionAvailable: companion,
59 selfHostedAvailable: selfHosted,
60 enterpriseAvailable: enterprise,
61 openrouterKeyAvailable: openrouter,
62 managedKeyAvailable: managed,
63 },
64 { orgPrivacyMode: orgPrivacy },
65 );
66 assert.ok(VALID_LANES.has(lane), `invalid lane returned: '${lane}'`);
67 }
68 });
69 });
70
71 describe('Data integrity — no mutation of input objects', () => {
72 it('selectLane does not mutate capabilities', () => {
73 const caps = { inBrowserAvailable: true, managedKeyAvailable: true };
74 const before = JSON.stringify(caps);
75 selectLane(caps, { orgPrivacyMode: true });
76 assert.equal(JSON.stringify(caps), before);
77 });
78
79 it('selectLane does not mutate preferences', () => {
80 const prefs = { keepOnDevice: true, orgPrivacyMode: false };
81 const before = JSON.stringify(prefs);
82 selectLane({ managedKeyAvailable: true }, prefs);
83 assert.equal(JSON.stringify(prefs), before);
84 });
85
86 it('enforceConsentPolicy does not mutate its params object', () => {
87 const params = {
88 lane: 'direct_provider',
89 containsPrivateData: true,
90 consentId: undefined,
91 isDelegate: false,
92 delegatedManagedAllowed: false,
93 };
94 const before = JSON.stringify({ ...params, consentId: null });
95 enforceConsentPolicy(params);
96 const after = JSON.stringify({ ...params, consentId: null });
97 assert.equal(before, after);
98 });
99 });
100
101 describe('Data integrity — sparse / partial capability objects (fail-closed)', () => {
102 it('empty capabilities: returns disabled', () => {
103 assert.equal(selectLane({}, {}), 'disabled');
104 });
105
106 it('only one boolean field provided: all others default to false', () => {
107 assert.equal(selectLane({ selfHostedAvailable: true }, {}), 'self_hosted');
108 });
109
110 it('unknown extra fields on capabilities: ignored safely', () => {
111 const lane = selectLane({ unknownField: true, managedKeyAvailable: true }, {});
112 assert.equal(lane, 'direct_provider');
113 });
114
115 it('unknown extra fields on preferences: ignored safely', () => {
116 const lane = selectLane({ managedKeyAvailable: true }, { unknownPref: true });
117 assert.equal(lane, 'direct_provider');
118 });
119 });
120
121 describe('Data integrity — enforceConsentPolicy return values are canonical', () => {
122 const validDecisions = new Set(['allow', 'cloud_consent_required', 'lane_policy_denied']);
123
124 it('all code paths return a canonical decision string', () => {
125 const cases = [
126 // non-managed lanes
127 ...['local', 'self_hosted', 'enterprise', 'openrouter', 'disabled'].map((lane) => ({
128 lane, containsPrivateData: true, consentId: undefined, isDelegate: true, delegatedManagedAllowed: false,
129 })),
130 // managed, allow
131 { lane: 'direct_provider', containsPrivateData: false, consentId: undefined, isDelegate: false, delegatedManagedAllowed: false },
132 // managed, consent required
133 { lane: 'direct_provider', containsPrivateData: true, consentId: undefined, isDelegate: false, delegatedManagedAllowed: false },
134 // managed, policy denied
135 { lane: 'direct_provider', containsPrivateData: false, consentId: 'cid', isDelegate: true, delegatedManagedAllowed: false },
136 ];
137 for (const c of cases) {
138 const d = enforceConsentPolicy(c);
139 assert.ok(validDecisions.has(d), `invalid decision: '${d}'`);
140 }
141 });
142 });
File History 1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 22 hours ago