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.
Files changed (163) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +15 -15
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  41. package/.next/standalone/.next/server/app/policies/page.js +3 -3
  42. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  52. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  55. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  58. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +20 -20
  59. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  60. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +2 -2
  62. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/src_hooks_1aveq0u._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__14o3ek1._.js → [root-of-the-server]__0tmz862._.js} +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
  73. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/ssr/{_0o4xkpl._.js → _0n0lja6._.js} +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +2 -2
  79. package/.next/standalone/.next/server/chunks/ssr/{_1-7sqrb._.js → _1p3iz2d._.js} +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +3 -3
  82. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0aiy-os._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +1 -1
  90. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  91. package/.next/standalone/.next/server/pages/404.html +1 -1
  92. package/.next/standalone/.next/server/pages/500.html +1 -1
  93. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  94. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  95. package/.next/standalone/.next/static/chunks/{2z7i-yg59w4pn.js → 0247hc9ath5t-.js} +1 -1
  96. package/.next/standalone/.next/static/chunks/{0ahfwmbkpgfw4.js → 03001k9jy-kst.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/{2vo7qbdbvnc0o.js → 06k7gsfnb7jkh.js} +1 -1
  98. package/.next/standalone/.next/static/chunks/0qejem4-zt-hy.js +1 -0
  99. package/.next/standalone/.next/static/chunks/{1v_tp3hm8wyhe.js → 0snylg3y1i47a.js} +1 -1
  100. package/.next/standalone/.next/static/chunks/1h0if8ky362as.js +1 -0
  101. package/.next/standalone/.next/static/chunks/{3bgot5v6f6s3c.js → 2qsrrrl2maqsb.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/{0bhidk90e-07f.css → 3_e_wg5_oay87.css} +1 -1
  103. package/.next/standalone/.next/static/chunks/3ns-egfh8i8i5.js +6 -0
  104. package/.next/standalone/.next/static/chunks/3rq7fjj9we0v3.js +1 -0
  105. package/.next/standalone/.next/static/chunks/42m0f2hh8vfb1.js +1 -0
  106. package/.next/standalone/app/actions/get-jev-config.ts +2 -2
  107. package/.next/standalone/app/actions/update-jev-config.ts +12 -9
  108. package/.next/standalone/app/components/jev-notices.tsx +10 -10
  109. package/.next/standalone/app/settings/jev-panel.tsx +11 -11
  110. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +2 -0
  111. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +26 -0
  112. package/.next/standalone/fp-cloud-cli/tests/test_output.py +27 -0
  113. package/.next/standalone/hermes-plugin/README.md +18 -8
  114. package/.next/standalone/package.json +10 -10
  115. package/.next/standalone/sdk/typescript/CHANGELOG.md +18 -1
  116. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +0 -274
  117. package/.next/standalone/server.js +1 -1
  118. package/bin/failproofai.mjs +33 -7
  119. package/dist/cli.mjs +664 -553
  120. package/dist/worker.mjs +164 -407
  121. package/hermes-plugin/README.md +18 -8
  122. package/package.json +10 -10
  123. package/scripts/build-policy-pack.mjs +6 -9
  124. package/src/hooks/cloud-connection.ts +12 -6
  125. package/src/hooks/custom-hooks-loader.ts +1 -1
  126. package/src/hooks/effective-reviewers.ts +50 -43
  127. package/src/hooks/handler.ts +25 -16
  128. package/src/hooks/hermes-update.ts +74 -0
  129. package/src/hooks/hook-activity-store.ts +3 -3
  130. package/src/hooks/integrations.ts +349 -55
  131. package/src/hooks/jev-activity.ts +3 -3
  132. package/src/hooks/jev-cli.ts +17 -17
  133. package/src/hooks/jev-cloud-connection.ts +4 -4
  134. package/src/hooks/manager.ts +3 -2
  135. package/src/hooks/pack-cli.ts +24 -23
  136. package/src/hooks/pack-manifest.ts +25 -2
  137. package/src/hooks/pack-store.ts +2 -2
  138. package/src/hooks/policy-authority.ts +51 -32
  139. package/src/hooks/policy-evaluator.ts +5 -5
  140. package/src/hooks/policy-registry.ts +5 -7
  141. package/src/hooks/policy-reviewability.ts +26 -10
  142. package/src/hooks/policy-types.ts +4 -4
  143. package/src/hooks/semantic/combine.ts +13 -13
  144. package/src/hooks/semantic/decide.ts +134 -29
  145. package/src/hooks/semantic/evaluator.ts +5 -5
  146. package/src/hooks/semantic/facts.ts +91 -2
  147. package/src/hooks/semantic/jev-client.ts +1 -1
  148. package/src/hooks/semantic/jev-config.ts +21 -12
  149. package/src/hooks/semantic/jev-review.ts +3 -3
  150. package/src/hooks/semantic/jev-stats.ts +17 -17
  151. package/src/hooks/semantic/pack-policies.ts +48 -48
  152. package/src/hooks/semantic/policies.ts +13 -425
  153. package/src/hooks/semantic/precondition-names.ts +1 -1
  154. package/src/hooks/semantic/preconditions.ts +1 -1
  155. package/src/hooks/semantic/types.ts +7 -1
  156. package/.next/standalone/.next/static/chunks/078gnymqoh3r4.js +0 -1
  157. package/.next/standalone/.next/static/chunks/1bu2-nv59ed6i.js +0 -1
  158. package/.next/standalone/.next/static/chunks/2a405_e1o26ol.js +0 -1
  159. package/.next/standalone/.next/static/chunks/36uhh9el_oz8e.js +0 -1
  160. package/.next/standalone/.next/static/chunks/3o3f1ibfci0p7.js +0 -6
  161. /package/.next/standalone/.next/static/{O_b5R1axf5cb4NxIXq2kS → z1C0kJVF0NCtWn5R88hW3}/_buildManifest.js +0 -0
  162. /package/.next/standalone/.next/static/{O_b5R1axf5cb4NxIXq2kS → z1C0kJVF0NCtWn5R88hW3}/_clientMiddlewareManifest.js +0 -0
  163. /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
- * shadow mode, say — would clear denies under the next config in enforce mode
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 === "shadow" || cfg.mode === "enforce" ? cfg.mode : DEFAULT_JEV_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 === "shadow" ? "shadow" : "two-tier",
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. Shadow mode's would-be clears are in
35
- * {@link JevStats.shadowClearsByPolicy}, so a renderer that prints only this
36
- * field says "nothing cleared" on a shadow-mode machine: print both.
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?: { shadow: number; enforce: number };
66
- /** What Jev would have cleared in shadow mode, where the regex result was enforced instead. */
67
- shadowClearsByPolicy?: Record<string, number>;
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: { shadow: 0, enforce: 0 },
164
- shadowClearsByPolicy: {},
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 shadowClearsByPolicy = new Counter();
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 === "shadow" ? shadowClearsByPolicy : clearsByPolicy;
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.shadowClearsByPolicy = shadowClearsByPolicy.toRecord();
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.shadowClearsByPolicy} as well as
221
- * `clearsByPolicy`: in shadow mode every clear Jev would have made is in the
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.shadowClearsByPolicy && Object.keys(s.shadowClearsByPolicy).length > 0) {
283
- lines.push(` Would clear: ${topCounts(s.shadowClearsByPolicy)} (shadow mode)`);
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.shadow > 0 && s.modes.enforce > 0) {
286
- lines.push(` Modes: enforce ${s.modes.enforce}, shadow ${s.modes.shadow}`);
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 semantic policy set this machine runs: a pack's, or the compiled-in one.
2
+ * Which Jev checks this machine asks: the ones its installed packs declare, and
3
+ * nothing else.
3
4
  *
4
- * ## The replacement rule
5
+ * ## No pack, no questions
5
6
  *
6
- * A FailproofAI pack that declares at least ONE `semantic` entry replaces
7
- * `SEMANTIC_POLICIES` wholesale. It mirrors the rule already in force for the
8
- * regex builtins — installing a pack stops the compiled builtins registering —
9
- * and it exists for the same reason: one source of truth, so a name collision
10
- * between a pack's `destructive-deletion` and the builtin of that name cannot
11
- * arise, and `reviewedBy: ["destructive-deletion"]` in a pack manifest cannot
12
- * silently mean the builtin's question set instead of the pack's.
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
- * Anyone else's checks are ADDED to the compiled-in set instead. Their names
15
- * cannot collide with it (a third party's claim to a builtin name is void:
16
- * `isReservedClaim`),
17
- * and replacing it would drop deny-mode checks like `credential-exfiltration`
18
- * that add denies the regex tier does not have — weaker, not noisier.
19
- *
20
- * Two packs that both declare entries CONCATENATE; a name declared by two packs
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, replacesBuiltinChecks } from "../effective-reviewers";
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, SEMANTIC_POLICIES, TASK_PROBES } from "./policies";
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
- * The real sixteen use `BUILTIN_QUESTION_CHARS` of it, so this is not a
99
- * constraint on the set we ship. A stranger's pack is added to them, so what it
100
- * may ask for is what they leave.
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
- /** What the compiled-in set spends of that budget when third-party checks join it. */
127
- export const BUILTIN_QUESTION_CHARS = SEMANTIC_POLICIES.reduce((n, p) => n + questionChars(p as SemanticManifestEntry), 0);
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, or the compiled-in set when none of them
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: SEMANTIC_POLICIES, fromPack: false, errors: [] };
186
+ if (declared.length === 0) return { policies: [], fromPack: false, errors: [] };
181
187
 
182
- // FailproofAI's own checks replace the compiled-in set; anyone else's join it
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[] = replace ? [] : [...SEMANTIC_POLICIES];
190
+ const policies: SemanticPolicy[] = [];
188
191
  const errors: string[] = [];
189
- const seen = new Set<string>(policies.map((p) => p.name));
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 = replace ? 0 : BUILTIN_QUESTION_CHARS;
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. The compiled-in set is
245
- // the honest answer — it is what the machine ran yesterday — and it is also
246
- // the safe one: what a pack's regex half names in `reviewedBy` will not match
247
- // it, so those policies stay hard rather than being cleared by questions
248
- // nobody validated.
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 the compiled-in set, which is the
266
- * same fail-open posture every other reader of that file takes, and here it also
267
- * fails in the safe direction: the set a pack's `reviewedBy` names is not the
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 SEMANTIC_POLICIES;
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