failproofai 1.0.8-beta.0 → 1.0.9-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +3 -3
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +20 -20
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_1aveq0u._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__14o3ek1._.js → [root-of-the-server]__0tmz862._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0o4xkpl._.js → _0n0lja6._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1-7sqrb._.js → _1p3iz2d._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0aiy-os._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
- package/.next/standalone/.next/static/chunks/{2z7i-yg59w4pn.js → 0247hc9ath5t-.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ahfwmbkpgfw4.js → 03001k9jy-kst.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2vo7qbdbvnc0o.js → 06k7gsfnb7jkh.js} +1 -1
- package/.next/standalone/.next/static/chunks/0qejem4-zt-hy.js +1 -0
- package/.next/standalone/.next/static/chunks/{1v_tp3hm8wyhe.js → 0snylg3y1i47a.js} +1 -1
- package/.next/standalone/.next/static/chunks/1h0if8ky362as.js +1 -0
- package/.next/standalone/.next/static/chunks/{3bgot5v6f6s3c.js → 2qsrrrl2maqsb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0bhidk90e-07f.css → 3_e_wg5_oay87.css} +1 -1
- package/.next/standalone/.next/static/chunks/3ns-egfh8i8i5.js +6 -0
- package/.next/standalone/.next/static/chunks/3rq7fjj9we0v3.js +1 -0
- package/.next/standalone/.next/static/chunks/42m0f2hh8vfb1.js +1 -0
- package/.next/standalone/app/actions/get-jev-config.ts +2 -2
- package/.next/standalone/app/actions/update-jev-config.ts +12 -9
- package/.next/standalone/app/components/jev-notices.tsx +10 -10
- package/.next/standalone/app/settings/jev-panel.tsx +11 -11
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +2 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +26 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +27 -0
- package/.next/standalone/hermes-plugin/README.md +18 -8
- package/.next/standalone/package.json +10 -10
- package/.next/standalone/sdk/typescript/CHANGELOG.md +18 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +0 -274
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +33 -7
- package/dist/cli.mjs +664 -553
- package/dist/worker.mjs +164 -407
- package/hermes-plugin/README.md +18 -8
- package/package.json +10 -10
- package/scripts/build-policy-pack.mjs +6 -9
- package/src/hooks/cloud-connection.ts +12 -6
- package/src/hooks/custom-hooks-loader.ts +1 -1
- package/src/hooks/effective-reviewers.ts +50 -43
- package/src/hooks/handler.ts +25 -16
- package/src/hooks/hermes-update.ts +74 -0
- package/src/hooks/hook-activity-store.ts +3 -3
- package/src/hooks/integrations.ts +349 -55
- package/src/hooks/jev-activity.ts +3 -3
- package/src/hooks/jev-cli.ts +17 -17
- package/src/hooks/jev-cloud-connection.ts +4 -4
- package/src/hooks/manager.ts +3 -2
- package/src/hooks/pack-cli.ts +24 -23
- package/src/hooks/pack-manifest.ts +25 -2
- package/src/hooks/pack-store.ts +2 -2
- package/src/hooks/policy-authority.ts +51 -32
- package/src/hooks/policy-evaluator.ts +5 -5
- package/src/hooks/policy-registry.ts +5 -7
- package/src/hooks/policy-reviewability.ts +26 -10
- package/src/hooks/policy-types.ts +4 -4
- package/src/hooks/semantic/combine.ts +13 -13
- package/src/hooks/semantic/decide.ts +134 -29
- package/src/hooks/semantic/evaluator.ts +5 -5
- package/src/hooks/semantic/facts.ts +91 -2
- package/src/hooks/semantic/jev-client.ts +1 -1
- package/src/hooks/semantic/jev-config.ts +21 -12
- package/src/hooks/semantic/jev-review.ts +3 -3
- package/src/hooks/semantic/jev-stats.ts +17 -17
- package/src/hooks/semantic/pack-policies.ts +48 -48
- package/src/hooks/semantic/policies.ts +13 -425
- package/src/hooks/semantic/precondition-names.ts +1 -1
- package/src/hooks/semantic/preconditions.ts +1 -1
- package/src/hooks/semantic/types.ts +7 -1
- package/.next/standalone/.next/static/chunks/078gnymqoh3r4.js +0 -1
- package/.next/standalone/.next/static/chunks/1bu2-nv59ed6i.js +0 -1
- package/.next/standalone/.next/static/chunks/2a405_e1o26ol.js +0 -1
- package/.next/standalone/.next/static/chunks/36uhh9el_oz8e.js +0 -1
- package/.next/standalone/.next/static/chunks/3o3f1ibfci0p7.js +0 -6
- /package/.next/standalone/.next/static/{O_b5R1axf5cb4NxIXq2kS → z1C0kJVF0NCtWn5R88hW3}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{O_b5R1axf5cb4NxIXq2kS → z1C0kJVF0NCtWn5R88hW3}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{O_b5R1axf5cb4NxIXq2kS → z1C0kJVF0NCtWn5R88hW3}/_ssgManifest.js +0 -0
|
@@ -114,7 +114,7 @@ function servedFromCache(response: unknown): boolean {
|
|
|
114
114
|
* `jev.json`, and the request alone does not say who answered it: two
|
|
115
115
|
* providers asked for the same model build byte-identical requests. Unscoped,
|
|
116
116
|
* an answer one config got — from a plain-http loopback proxy T1 allows only in
|
|
117
|
-
*
|
|
117
|
+
* observe mode, say — would clear denies under the next config in enforce mode
|
|
118
118
|
* without that provider ever being asked. The scope is only hashed into the
|
|
119
119
|
* cache key, never stored, so a URL carrying a credential is safe here.
|
|
120
120
|
*/
|
|
@@ -152,7 +152,7 @@ export interface JevCallContext {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
export function resolveMode(cfg: JevConfig): JevMode {
|
|
155
|
-
return cfg.mode === "
|
|
155
|
+
return cfg.mode === "observe" || cfg.mode === "enforce" ? cfg.mode : DEFAULT_JEV_MODE;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
/**
|
|
@@ -359,7 +359,7 @@ export function startJevReview(cfg: JevConfig, call: JevCallContext): TwoTierRev
|
|
|
359
359
|
sessionId: call.sessionId,
|
|
360
360
|
cli: call.cli,
|
|
361
361
|
eventType: call.eventType,
|
|
362
|
-
applied: abandoned || review.kind !== "answered" ? "legacy-fallback" : mode === "
|
|
362
|
+
applied: abandoned || review.kind !== "answered" ? "legacy-fallback" : mode === "observe" ? "observe" : "two-tier",
|
|
363
363
|
});
|
|
364
364
|
appendVerdictLog(hit ? { ...row, cached: true } : row);
|
|
365
365
|
}
|
|
@@ -31,9 +31,9 @@ export interface JevStats {
|
|
|
31
31
|
latencyP95Ms: number | null;
|
|
32
32
|
/**
|
|
33
33
|
* Reviewable policies Jev cleared, by name — enforce mode only, where a
|
|
34
|
-
* clear changed the outcome.
|
|
35
|
-
* {@link JevStats.
|
|
36
|
-
* field says "nothing cleared" on
|
|
34
|
+
* clear changed the outcome. Observe mode's would-be clears are in
|
|
35
|
+
* {@link JevStats.observeClearsByPolicy}, so a renderer that prints only this
|
|
36
|
+
* field says "nothing cleared" on an observe-mode machine: print both.
|
|
37
37
|
*/
|
|
38
38
|
clearsByPolicy: Record<string, number>;
|
|
39
39
|
// The fields below are optional in the TYPE only so that a caller written
|
|
@@ -62,9 +62,9 @@ export interface JevStats {
|
|
|
62
62
|
*/
|
|
63
63
|
decisions?: { allow: number; instruct: number; deny: number };
|
|
64
64
|
/** Consulted calls (`total`) per rollout mode; a row written without a mode is counted in neither. */
|
|
65
|
-
modes?: {
|
|
66
|
-
/** What Jev would have cleared in
|
|
67
|
-
|
|
65
|
+
modes?: { observe: number; enforce: number };
|
|
66
|
+
/** What Jev would have cleared in observe mode, where the regex result was enforced instead. */
|
|
67
|
+
observeClearsByPolicy?: Record<string, number>;
|
|
68
68
|
/** Model ids that answered, by count. */
|
|
69
69
|
models?: Record<string, number>;
|
|
70
70
|
}
|
|
@@ -160,14 +160,14 @@ export function computeJevStats(
|
|
|
160
160
|
notConsulted: 0,
|
|
161
161
|
noRequest: 0,
|
|
162
162
|
decisions: { allow: 0, instruct: 0, deny: 0 },
|
|
163
|
-
modes: {
|
|
164
|
-
|
|
163
|
+
modes: { observe: 0, enforce: 0 },
|
|
164
|
+
observeClearsByPolicy: {},
|
|
165
165
|
models: {},
|
|
166
166
|
};
|
|
167
167
|
const latencies: number[] = [];
|
|
168
168
|
const fallbackReasons = new Counter();
|
|
169
169
|
const clearsByPolicy = new Counter();
|
|
170
|
-
const
|
|
170
|
+
const observeClearsByPolicy = new Counter();
|
|
171
171
|
const models = new Counter();
|
|
172
172
|
|
|
173
173
|
for (const raw of entries) {
|
|
@@ -197,13 +197,13 @@ export function computeJevStats(
|
|
|
197
197
|
if (e.jevDecision) stats.decisions[e.jevDecision] += 1;
|
|
198
198
|
if (e.jevLatencyMs !== undefined) latencies.push(e.jevLatencyMs);
|
|
199
199
|
if (e.jevModel) models.bump(e.jevModel);
|
|
200
|
-
const clears = e.jevMode === "
|
|
200
|
+
const clears = e.jevMode === "observe" ? observeClearsByPolicy : clearsByPolicy;
|
|
201
201
|
for (const name of e.jevCleared ?? []) clears.bump(name);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
stats.fallbackReasons = fallbackReasons.toRecord();
|
|
205
205
|
stats.clearsByPolicy = clearsByPolicy.toRecord();
|
|
206
|
-
stats.
|
|
206
|
+
stats.observeClearsByPolicy = observeClearsByPolicy.toRecord();
|
|
207
207
|
stats.models = models.toRecord();
|
|
208
208
|
stats.fallbackRate = stats.total > 0 ? stats.fallbacks / stats.total : 0;
|
|
209
209
|
latencies.sort((a, b) => a - b);
|
|
@@ -217,8 +217,8 @@ export function computeJevStats(
|
|
|
217
217
|
* {@link clampJevStatsWindow}), read from the hook activity store. Never
|
|
218
218
|
* throws: an unreadable store reads as no activity.
|
|
219
219
|
*
|
|
220
|
-
* A renderer must show {@link JevStats.
|
|
221
|
-
* `clearsByPolicy`: in
|
|
220
|
+
* A renderer must show {@link JevStats.observeClearsByPolicy} as well as
|
|
221
|
+
* `clearsByPolicy`: in observe mode every clear Jev would have made is in the
|
|
222
222
|
* former, and the latter is empty. {@link formatJevStats} prints both.
|
|
223
223
|
*/
|
|
224
224
|
export async function jevStats(opts: { windowMs?: number; now?: number } = {}): Promise<JevStatsDetail> {
|
|
@@ -279,11 +279,11 @@ export function formatJevStats(s: JevStats): string {
|
|
|
279
279
|
lines.push(...notAsked);
|
|
280
280
|
if (s.latencyP50Ms !== null) lines.push(` Latency: p50 ${s.latencyP50Ms} ms, p95 ${s.latencyP95Ms} ms`);
|
|
281
281
|
if (Object.keys(s.clearsByPolicy).length > 0) lines.push(` Cleared: ${topCounts(s.clearsByPolicy)}`);
|
|
282
|
-
if (s.
|
|
283
|
-
lines.push(` Would clear: ${topCounts(s.
|
|
282
|
+
if (s.observeClearsByPolicy && Object.keys(s.observeClearsByPolicy).length > 0) {
|
|
283
|
+
lines.push(` Would clear: ${topCounts(s.observeClearsByPolicy)} (observe mode)`);
|
|
284
284
|
}
|
|
285
|
-
if (s.modes && s.modes.
|
|
286
|
-
lines.push(` Modes: enforce ${s.modes.enforce},
|
|
285
|
+
if (s.modes && s.modes.observe > 0 && s.modes.enforce > 0) {
|
|
286
|
+
lines.push(` Modes: enforce ${s.modes.enforce}, observe ${s.modes.observe}`);
|
|
287
287
|
}
|
|
288
288
|
return lines.join("\n");
|
|
289
289
|
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which
|
|
2
|
+
* Which Jev checks this machine asks: the ones its installed packs declare, and
|
|
3
|
+
* nothing else.
|
|
3
4
|
*
|
|
4
|
-
* ##
|
|
5
|
+
* ## No pack, no questions
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* The npm package ships NO Jev checks. The sixteen FailproofAI writes are
|
|
8
|
+
* published as the `FailproofAI/jev-policies` pack, and a machine asks them only
|
|
9
|
+
* after `failproofai policies add FailproofAI/jev-policies`. With no installed
|
|
10
|
+
* pack declaring a `semantic` entry the set is EMPTY: nothing is asked, no
|
|
11
|
+
* request is sent (the hook path does not even start a review —
|
|
12
|
+
* `jevChecksInstalled` in `effective-reviewers.ts`), and no regex verdict can be
|
|
13
|
+
* cleared, because the reviewer names come from the same packs and there are
|
|
14
|
+
* none. That holds whether or not the machine is Jev-configured or connected to
|
|
15
|
+
* FailproofAI Cloud: configuring a provider says where to ask, a pack says what.
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* keeps the first and drops the later one, because the answer map is keyed by
|
|
22
|
-
* policy name and the second would overwrite the first's questions in the
|
|
23
|
-
* compiled request.
|
|
17
|
+
* Several declaring packs CONCATENATE, FailproofAI's first. A name declared by
|
|
18
|
+
* two packs keeps the first and drops the later one, because the answer map is
|
|
19
|
+
* keyed by policy name and the second would overwrite the first's questions in
|
|
20
|
+
* the compiled request. The sixteen FailproofAI names are reserved: a pack not
|
|
21
|
+
* installed from a FailproofAI repository that declares one is ignored for that
|
|
22
|
+
* name (`isReservedClaim`), so it cannot become the question that clears the
|
|
23
|
+
* core pack's policies.
|
|
24
24
|
*
|
|
25
25
|
* ## Where the manifest ends and this begins
|
|
26
26
|
*
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* regex policies cover — a machine locked out over a typo in the half of the
|
|
40
40
|
* system whose job is to let more real work through.
|
|
41
41
|
*/
|
|
42
|
-
import { contestedSemanticNames, isFirstPartyPack, isReservedClaim, jevPacks
|
|
42
|
+
import { contestedSemanticNames, isFirstPartyPack, isReservedClaim, jevPacks } from "../effective-reviewers";
|
|
43
43
|
import { hookLogWarn } from "../hook-logger";
|
|
44
44
|
import {
|
|
45
45
|
packSemantic,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
} from "../pack-manifest";
|
|
51
51
|
import { MAX_REQUEST_CHARS, userAskedQuestion } from "./compile";
|
|
52
52
|
import { MAX_STATE_CHARS } from "./envelope";
|
|
53
|
-
import { INJECTION_PROBE, SCOPE_PROBE,
|
|
53
|
+
import { INJECTION_PROBE, SCOPE_PROBE, TASK_PROBES } from "./policies";
|
|
54
54
|
import { preconditionFor } from "./preconditions";
|
|
55
55
|
import { isPackPreconditionName } from "./precondition-names";
|
|
56
56
|
import type { NoulQuestion, SemanticPolicy } from "./types";
|
|
@@ -95,9 +95,9 @@ const GLOBAL_QUESTION_CHARS = Math.max(
|
|
|
95
95
|
* "somebody installed a big pack", and the flag that was supposed to be
|
|
96
96
|
* unreachable from ordinary work becomes routine.
|
|
97
97
|
*
|
|
98
|
-
*
|
|
99
|
-
* constraint on the set we ship.
|
|
100
|
-
*
|
|
98
|
+
* `FailproofAI/jev-policies` uses `JEV_POLICIES_QUESTION_CHARS` of it, so this
|
|
99
|
+
* is not a constraint on the set we ship. FailproofAI's packs spend the budget
|
|
100
|
+
* first, so a stranger's pack installed beside that one gets what it leaves.
|
|
101
101
|
*/
|
|
102
102
|
export const MAX_PACK_QUESTION_CHARS = MAX_REQUEST_CHARS - MAX_STATE_CHARS - GLOBAL_QUESTION_CHARS;
|
|
103
103
|
|
|
@@ -123,8 +123,15 @@ export function questionChars(entry: SemanticManifestEntry): number {
|
|
|
123
123
|
return JSON.stringify(questions).length;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
/**
|
|
127
|
-
|
|
126
|
+
/**
|
|
127
|
+
* What `FailproofAI/jev-policies`' sixteen checks spend of that budget, which a
|
|
128
|
+
* pack from anyone else shares with them on a machine that has both installed.
|
|
129
|
+
* Measured, not chosen: `pack-semantic-registry.test.ts` pins it to the
|
|
130
|
+
* reference copy in `__tests__/fixtures/jev-policies.ts`. Only `publish` reads
|
|
131
|
+
* it, to warn an author before release; the machine measures what is actually
|
|
132
|
+
* installed.
|
|
133
|
+
*/
|
|
134
|
+
export const JEV_POLICIES_QUESTION_CHARS = 18490;
|
|
128
135
|
|
|
129
136
|
export interface ResolvedSemanticPolicies {
|
|
130
137
|
policies: ReadonlyArray<SemanticPolicy>;
|
|
@@ -166,8 +173,7 @@ function toSemanticPolicy(entry: SemanticManifestEntry, pack: { id: string; vers
|
|
|
166
173
|
}
|
|
167
174
|
|
|
168
175
|
/**
|
|
169
|
-
* The semantic set these packs declare
|
|
170
|
-
* declares any.
|
|
176
|
+
* The semantic set these packs declare — empty when none of them declares any.
|
|
171
177
|
*
|
|
172
178
|
* Pure: it takes the packs rather than reading them, so the caller that already
|
|
173
179
|
* has them does not read `installed.json` a second time and a test does not need
|
|
@@ -177,16 +183,13 @@ export function semanticPoliciesFromPacks(
|
|
|
177
183
|
packs: ReadonlyArray<Pick<ResolvedPack, "id" | "semantic"> & { source?: string; version?: string }>,
|
|
178
184
|
): ResolvedSemanticPolicies {
|
|
179
185
|
const declared = packs.filter((p) => packSemantic(p).length > 0);
|
|
180
|
-
if (declared.length === 0) return { policies:
|
|
186
|
+
if (declared.length === 0) return { policies: [], fromPack: false, errors: [] };
|
|
181
187
|
|
|
182
|
-
//
|
|
183
|
-
// (`replacesBuiltinChecks`, which the reviewer set applies too). First-party
|
|
184
|
-
// packs spend the budget first, so install order cannot starve them.
|
|
185
|
-
const replace = replacesBuiltinChecks(declared);
|
|
188
|
+
// First-party packs spend the budget first, so install order cannot starve them.
|
|
186
189
|
const ordered = [...declared.filter((p) => isFirstPartyPack(p)), ...declared.filter((p) => !isFirstPartyPack(p))];
|
|
187
|
-
const policies: SemanticPolicy[] =
|
|
190
|
+
const policies: SemanticPolicy[] = [];
|
|
188
191
|
const errors: string[] = [];
|
|
189
|
-
const seen = new Set<string>(
|
|
192
|
+
const seen = new Set<string>();
|
|
190
193
|
// A name two packs declare DIFFERENTLY is asked for nobody. Keeping the first
|
|
191
194
|
// was the escalation: the question that decides another pack's policies came
|
|
192
195
|
// from whichever pack was listed first, so installing a permissive
|
|
@@ -196,7 +199,7 @@ export function semanticPoliciesFromPacks(
|
|
|
196
199
|
// be the same name — a check in the set with nobody's question, or a question
|
|
197
200
|
// nobody may name, are both worse than neither.
|
|
198
201
|
const contested = contestedSemanticNames(declared);
|
|
199
|
-
let spent =
|
|
202
|
+
let spent = 0;
|
|
200
203
|
for (const pack of ordered) {
|
|
201
204
|
for (const entry of packSemantic(pack)) {
|
|
202
205
|
if (isReservedClaim(pack, entry.name)) {
|
|
@@ -241,13 +244,11 @@ export function semanticPoliciesFromPacks(
|
|
|
241
244
|
}
|
|
242
245
|
}
|
|
243
246
|
|
|
244
|
-
// Every entry a declaring pack shipped was unusable
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
if (policies.length === (replace ? 0 : SEMANTIC_POLICIES.length)) return { policies: SEMANTIC_POLICIES, fromPack: false, errors };
|
|
250
|
-
return { policies, fromPack: true, errors };
|
|
247
|
+
// Every entry a declaring pack shipped was unusable: nothing is asked, and
|
|
248
|
+
// `fromPack` says no pack supplied anything. There is no compiled-in set to
|
|
249
|
+
// fall back to, and that is the safe direction — nothing is asked, so nothing
|
|
250
|
+
// a `reviewedBy` names is ever answered, and those policies stay hard.
|
|
251
|
+
return { policies, fromPack: policies.length > 0, errors };
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
const warned = new Set<string>();
|
|
@@ -262,10 +263,9 @@ const warned = new Set<string>();
|
|
|
262
263
|
* exactly that reason. The read costs one digest per pack against a call that is
|
|
263
264
|
* about to spend up to three seconds on the network.
|
|
264
265
|
*
|
|
265
|
-
* Never throws. An unreadable manifest yields
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* builtin set, so nothing gets cleared by a policy nobody could read.
|
|
266
|
+
* Never throws. An unreadable manifest yields NO checks: nothing is asked and
|
|
267
|
+
* nothing is cleared, so every regex verdict stands. There is deliberately no
|
|
268
|
+
* compiled-in set to fall back to — the package ships none.
|
|
269
269
|
*/
|
|
270
270
|
export function resolveSemanticPolicies(cli?: string): ReadonlyArray<SemanticPolicy> {
|
|
271
271
|
let packs: ReadonlyArray<ResolvedPack> = [];
|
|
@@ -275,7 +275,7 @@ export function resolveSemanticPolicies(cli?: string): ReadonlyArray<SemanticPol
|
|
|
275
275
|
packs = read.packs;
|
|
276
276
|
manifestErrors = read.warnings ?? [];
|
|
277
277
|
} catch {
|
|
278
|
-
return
|
|
278
|
+
return [];
|
|
279
279
|
}
|
|
280
280
|
const resolved = semanticPoliciesFromPacks(jevPacks(packs, cli));
|
|
281
281
|
// Once per process per message, like `warnAuthority`: this runs on every gate
|