model-runtime-lane-integration.test.mjs
209 lines 7.4 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * Tier 2 — INTEGRATION: model-runtime-lane pipeline
3 *
4 * Tests that selectLane and enforceConsentPolicy compose correctly into the
5 * full "pick lane → check policy" pipeline that a concrete adapter will execute.
6 * Tests realistic end-to-end scenarios (individual user, org, delegate, fallback chains)
7 * without any network I/O.
8 *
9 * Reference: docs/COMPANION-APP-PHASE-1-ADAPTER-SEAM.md §1, §3
10 */
11 import { describe, it } from 'node:test';
12 import assert from 'node:assert/strict';
13 import {
14 selectLane,
15 isManagedLane,
16 enforceConsentPolicy,
17 } from '../lib/model-runtime-lane.mjs';
18
19 /**
20 * Simulates the pipeline a concrete KnowtationModelRuntimeAdapter will run:
21 * 1. selectLane → determines the runtime lane
22 * 2. isManagedLane → determines billing responsibility
23 * 3. enforceConsentPolicy → determines whether to proceed
24 *
25 * @param {{ capabilities: object, preferences: object, containsPrivateData: boolean, consentId?: string }} params
26 * @returns {{ lane: string, metered: boolean, decision: string }}
27 */
28 function runPipeline({ capabilities, preferences, containsPrivateData, consentId }) {
29 const lane = selectLane(capabilities, preferences);
30 const metered = isManagedLane(lane);
31 const decision = enforceConsentPolicy({
32 lane,
33 containsPrivateData,
34 consentId,
35 isDelegate: preferences.isDelegate ?? false,
36 delegatedManagedAllowed: preferences.delegatedManagedAllowed ?? false,
37 });
38 return { lane, metered, decision };
39 }
40
41 describe('Integration — individual user with on-device compute', () => {
42 it('in-browser: allow, not metered', () => {
43 const result = runPipeline({
44 capabilities: { inBrowserAvailable: true, managedKeyAvailable: true },
45 preferences: {},
46 containsPrivateData: true,
47 });
48 assert.equal(result.lane, 'local');
49 assert.equal(result.metered, false);
50 assert.equal(result.decision, 'allow');
51 });
52
53 it('companion: allow, not metered, even with private data and no consent', () => {
54 const result = runPipeline({
55 capabilities: { companionAvailable: true, managedKeyAvailable: true },
56 preferences: {},
57 containsPrivateData: true,
58 });
59 assert.equal(result.lane, 'local');
60 assert.equal(result.metered, false);
61 assert.equal(result.decision, 'allow');
62 });
63 });
64
65 describe('Integration — individual user, no on-device compute, non-private data', () => {
66 it('falls to managed: allow, metered', () => {
67 const result = runPipeline({
68 capabilities: { managedKeyAvailable: true },
69 preferences: {},
70 containsPrivateData: false,
71 });
72 assert.equal(result.lane, 'direct_provider');
73 assert.equal(result.metered, true);
74 assert.equal(result.decision, 'allow');
75 });
76 });
77
78 describe('Integration — individual user, managed lane, private data without consent', () => {
79 it('consent required: metered but policy blocks', () => {
80 const result = runPipeline({
81 capabilities: { managedKeyAvailable: true },
82 preferences: {},
83 containsPrivateData: true,
84 consentId: undefined,
85 });
86 assert.equal(result.lane, 'direct_provider');
87 assert.equal(result.metered, true);
88 assert.equal(result.decision, 'cloud_consent_required');
89 });
90
91 it('allow after consent provided', () => {
92 const result = runPipeline({
93 capabilities: { managedKeyAvailable: true },
94 preferences: {},
95 containsPrivateData: true,
96 consentId: 'cid-abc',
97 });
98 assert.equal(result.lane, 'direct_provider');
99 assert.equal(result.metered, true);
100 assert.equal(result.decision, 'allow');
101 });
102 });
103
104 describe('Integration — org privacy mode', () => {
105 it('self-hosted: allow, not metered, private data no consent needed', () => {
106 const result = runPipeline({
107 capabilities: { selfHostedAvailable: true, managedKeyAvailable: true },
108 preferences: { orgPrivacyMode: true },
109 containsPrivateData: true,
110 });
111 assert.equal(result.lane, 'self_hosted');
112 assert.equal(result.metered, false);
113 assert.equal(result.decision, 'allow');
114 });
115
116 it('disabled when org privacy mode and nothing available', () => {
117 const result = runPipeline({
118 capabilities: { managedKeyAvailable: true },
119 preferences: { orgPrivacyMode: true },
120 containsPrivateData: false,
121 });
122 assert.equal(result.lane, 'disabled');
123 assert.equal(result.metered, false);
124 assert.equal(result.decision, 'allow');
125 });
126 });
127
128 describe('Integration — BYO key (openrouter)', () => {
129 it('openrouter: allow, not metered, even with private data', () => {
130 const result = runPipeline({
131 capabilities: { openrouterKeyAvailable: true, managedKeyAvailable: true },
132 preferences: {},
133 containsPrivateData: true,
134 });
135 assert.equal(result.lane, 'openrouter');
136 assert.equal(result.metered, false);
137 assert.equal(result.decision, 'allow');
138 });
139 });
140
141 describe('Integration — delegate scenarios (D1.4)', () => {
142 it('delegate without owner opt-in: lane_policy_denied even with consentId', () => {
143 const result = runPipeline({
144 capabilities: { managedKeyAvailable: true },
145 preferences: { isDelegate: true, delegatedManagedAllowed: false },
146 containsPrivateData: false,
147 consentId: 'cid-999',
148 });
149 assert.equal(result.lane, 'direct_provider');
150 assert.equal(result.metered, true);
151 assert.equal(result.decision, 'lane_policy_denied');
152 });
153
154 it('delegate with owner opt-in, non-private: allow', () => {
155 const result = runPipeline({
156 capabilities: { managedKeyAvailable: true },
157 preferences: { isDelegate: true, delegatedManagedAllowed: true },
158 containsPrivateData: false,
159 });
160 assert.equal(result.lane, 'direct_provider');
161 assert.equal(result.decision, 'allow');
162 });
163
164 it('delegate with owner opt-in, private data, no consent: cloud_consent_required', () => {
165 const result = runPipeline({
166 capabilities: { managedKeyAvailable: true },
167 preferences: { isDelegate: true, delegatedManagedAllowed: true },
168 containsPrivateData: true,
169 consentId: undefined,
170 });
171 assert.equal(result.lane, 'direct_provider');
172 assert.equal(result.decision, 'cloud_consent_required');
173 });
174
175 it('delegate routing to local: policy does not apply, always allow', () => {
176 const result = runPipeline({
177 capabilities: { companionAvailable: true },
178 preferences: { isDelegate: true, delegatedManagedAllowed: false },
179 containsPrivateData: true,
180 });
181 assert.equal(result.lane, 'local');
182 assert.equal(result.metered, false);
183 assert.equal(result.decision, 'allow');
184 });
185 });
186
187 describe('Integration — D2.2 fallback chain (keepOnDevice + no local compute)', () => {
188 it('managed lane selected but consent required for private data', () => {
189 // Scenario: user toggled "keep on device" but has no WebGPU/companion.
190 // D2.2: fall through to managed-with-explicit-consent.
191 const result = runPipeline({
192 capabilities: { managedKeyAvailable: true },
193 preferences: { keepOnDevice: true },
194 containsPrivateData: true,
195 });
196 assert.equal(result.lane, 'direct_provider');
197 assert.equal(result.decision, 'cloud_consent_required');
198 });
199
200 it('managed lane + keepOnDevice + non-private: no consent barrier', () => {
201 const result = runPipeline({
202 capabilities: { managedKeyAvailable: true },
203 preferences: { keepOnDevice: true },
204 containsPrivateData: false,
205 });
206 assert.equal(result.lane, 'direct_provider');
207 assert.equal(result.decision, 'allow');
208 });
209 });
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago