failproofai 1.0.8 → 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 (160) 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 +4 -4
  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]__0tmz862._.js +3 -0
  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/{_0-vcssj._.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/_1p3iz2d._.js +23 -0
  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/src_hooks_effective-reviewers_ts_1h4wtvo._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +1 -1
  89. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  90. package/.next/standalone/.next/server/pages/404.html +1 -1
  91. package/.next/standalone/.next/server/pages/500.html +1 -1
  92. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  93. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  94. package/.next/standalone/.next/static/chunks/{3c3qbmosdjl6w.js → 0247hc9ath5t-.js} +1 -1
  95. package/.next/standalone/.next/static/chunks/{0m-9d6yn9hx4j.js → 03001k9jy-kst.js} +1 -1
  96. package/.next/standalone/.next/static/chunks/{2qdpj67x6ifk_.js → 06k7gsfnb7jkh.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/0qejem4-zt-hy.js +1 -0
  98. package/.next/standalone/.next/static/chunks/{21uv-uusw329x.js → 0snylg3y1i47a.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/1h0if8ky362as.js +1 -0
  100. package/.next/standalone/.next/static/chunks/{0wbjy0zo-m7is.js → 2qsrrrl2maqsb.js} +1 -1
  101. package/.next/standalone/.next/static/chunks/{0bhidk90e-07f.css → 3_e_wg5_oay87.css} +1 -1
  102. package/.next/standalone/.next/static/chunks/3ns-egfh8i8i5.js +6 -0
  103. package/.next/standalone/.next/static/chunks/3rq7fjj9we0v3.js +1 -0
  104. package/.next/standalone/.next/static/chunks/42m0f2hh8vfb1.js +1 -0
  105. package/.next/standalone/app/actions/get-jev-config.ts +2 -2
  106. package/.next/standalone/app/actions/update-jev-config.ts +12 -9
  107. package/.next/standalone/app/components/jev-notices.tsx +10 -10
  108. package/.next/standalone/app/settings/jev-panel.tsx +11 -11
  109. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +2 -0
  110. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +26 -0
  111. package/.next/standalone/fp-cloud-cli/tests/test_output.py +27 -0
  112. package/.next/standalone/hermes-plugin/README.md +18 -8
  113. package/.next/standalone/package.json +10 -10
  114. package/.next/standalone/server.js +1 -1
  115. package/bin/failproofai.mjs +33 -7
  116. package/dist/cli.mjs +556 -521
  117. package/dist/worker.mjs +56 -375
  118. package/hermes-plugin/README.md +18 -8
  119. package/package.json +10 -10
  120. package/scripts/build-policy-pack.mjs +6 -9
  121. package/src/hooks/cloud-connection.ts +12 -6
  122. package/src/hooks/custom-hooks-loader.ts +1 -1
  123. package/src/hooks/effective-reviewers.ts +50 -43
  124. package/src/hooks/handler.ts +25 -16
  125. package/src/hooks/hermes-update.ts +74 -0
  126. package/src/hooks/hook-activity-store.ts +3 -3
  127. package/src/hooks/integrations.ts +349 -55
  128. package/src/hooks/jev-activity.ts +3 -3
  129. package/src/hooks/jev-cli.ts +17 -17
  130. package/src/hooks/jev-cloud-connection.ts +4 -4
  131. package/src/hooks/manager.ts +3 -2
  132. package/src/hooks/pack-cli.ts +24 -23
  133. package/src/hooks/pack-manifest.ts +25 -2
  134. package/src/hooks/pack-store.ts +2 -2
  135. package/src/hooks/policy-authority.ts +51 -32
  136. package/src/hooks/policy-evaluator.ts +5 -5
  137. package/src/hooks/policy-registry.ts +5 -7
  138. package/src/hooks/policy-reviewability.ts +26 -10
  139. package/src/hooks/policy-types.ts +4 -4
  140. package/src/hooks/semantic/combine.ts +13 -13
  141. package/src/hooks/semantic/evaluator.ts +5 -5
  142. package/src/hooks/semantic/jev-client.ts +1 -1
  143. package/src/hooks/semantic/jev-config.ts +21 -12
  144. package/src/hooks/semantic/jev-review.ts +3 -3
  145. package/src/hooks/semantic/jev-stats.ts +17 -17
  146. package/src/hooks/semantic/pack-policies.ts +48 -48
  147. package/src/hooks/semantic/policies.ts +13 -425
  148. package/src/hooks/semantic/precondition-names.ts +1 -1
  149. package/src/hooks/semantic/preconditions.ts +1 -1
  150. package/src/hooks/semantic/types.ts +1 -1
  151. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13t1zkw._.js +0 -3
  152. package/.next/standalone/.next/server/chunks/ssr/_13kfn90._.js +0 -23
  153. package/.next/standalone/.next/static/chunks/06dnzbolj00mc.js +0 -6
  154. package/.next/standalone/.next/static/chunks/16f3fa-lx38hk.js +0 -1
  155. package/.next/standalone/.next/static/chunks/2g2tki08kdhie.js +0 -1
  156. package/.next/standalone/.next/static/chunks/3-nbtkhg9y-1j.js +0 -1
  157. package/.next/standalone/.next/static/chunks/355km0ihuqo1p.js +0 -1
  158. /package/.next/standalone/.next/static/{5yKM8NoTOpUI0MoQl8eo5 → z1C0kJVF0NCtWn5R88hW3}/_buildManifest.js +0 -0
  159. /package/.next/standalone/.next/static/{5yKM8NoTOpUI0MoQl8eo5 → z1C0kJVF0NCtWn5R88hW3}/_clientMiddlewareManifest.js +0 -0
  160. /package/.next/standalone/.next/static/{5yKM8NoTOpUI0MoQl8eo5 → z1C0kJVF0NCtWn5R88hW3}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@
4
4
  * `config --token` with a key that carries `jev:evaluate` stores the key in the
5
5
  * `jev` slot of `credentials.json` (`cloud-connection.ts`) and then, ONLY when
6
6
  * this machine has no `jev.json` at all, writes one that turns Jev on through
7
- * FailproofAI Cloud in shadow mode — logged, never enforced, until its owner
7
+ * FailproofAI Cloud in observe mode — logged, never enforced, until its owner
8
8
  * says otherwise. Never under `--no-transcripts`: that connection asked for
9
9
  * decisions only, so it stores the key and says Jev is available, and
10
10
  * `jev setup --provider failproofai` is the opt-in. `config --disconnect`
@@ -29,7 +29,7 @@
29
29
  * status screen. A BYOK file keeps working without the Cloud and is not the
30
30
  * Cloud's to delete, so it stays; so does a file this build cannot read, and a
31
31
  * Cloud file switched off — `--mode off` is the owner's opt-out, and deleting
32
- * it would let the next connect write a fresh shadow file. The
32
+ * it would let the next connect write a fresh observe-mode file. The
33
33
  * file is moved aside before it is judged, so the file judged is the file
34
34
  * deleted — see `removeCloudJevConfig`.
35
35
  *
@@ -67,7 +67,7 @@ import {
67
67
  } from "./semantic/jev-config";
68
68
 
69
69
  /** The mode a Cloud `jev.json` starts in (the user's decision: log first, enforce later). */
70
- export const CLOUD_JEV_INITIAL_MODE = "shadow" as const;
70
+ export const CLOUD_JEV_INITIAL_MODE = "observe" as const;
71
71
 
72
72
  export type CloudJevConfigWrite =
73
73
  | { status: "written"; path: string; mode: typeof CLOUD_JEV_INITIAL_MODE; baseUrl: string }
@@ -145,7 +145,7 @@ export function existingJevConfig(cloudBase: string): CloudJevConfigWrite | null
145
145
  * Asked the way a hook asks (`inspectJevConfig`), so "on" here means a tool
146
146
  * call's next Jev request really goes to FailproofAI Cloud.
147
147
  */
148
- export function cloudJevRunningMode(): "shadow" | "enforce" | null {
148
+ export function cloudJevRunningMode(): "observe" | "enforce" | null {
149
149
  try {
150
150
  const r = inspectJevConfig();
151
151
  if (r.status !== "ok" || r.config.provider !== JEV_CLOUD_PROVIDER) return null;
@@ -28,7 +28,7 @@ import { customPoliciesDir, globalPolicyConfigFile } from "./fp-home";
28
28
  import { readActiveCloudManagedPolicies } from "./cloud-managed-policies";
29
29
  import { CORE_SOURCE, addPack, setPackPolicyEnabled } from "./pack-store";
30
30
  import type { ResolvedPack } from "./pack-manifest";
31
- import { hasInstalledPacks, readInstalledPacks } from "./pack-manifest";
31
+ import { hasInstalledRegexPacks, readInstalledPacks } from "./pack-manifest";
32
32
  import { packPolicyParamKey } from "./policy-evaluator";
33
33
  import { probeDaemonPolicyEvaluation } from "./daemon-service";
34
34
  import {
@@ -654,7 +654,8 @@ async function installHooksImpl(
654
654
  //
655
655
  // With a pack already installed the names are switched on individually
656
656
  // instead, which is additive and touches nothing else.
657
- if (!hasInstalledPacks()) {
657
+ // A Jev-only pack has no policy to switch on, so it does not count here.
658
+ if (!hasInstalledRegexPacks()) {
658
659
  // Fetched, not unpacked from this package: there is no copy in here any
659
660
  // more. That makes this the one path in `policies --install` that needs
660
661
  // the network, so its failure is reported rather than thrown — the names
@@ -26,7 +26,7 @@ import { compareVersions, parseSemver } from "./semver-precedence";
26
26
  // budget, which means reaching the semantic side. This is a CLI module — loaded
27
27
  // by `failproofai publish`, never by a hook — so the rule that keeps those
28
28
  // modules off an unconfigured machine's hook path does not apply here.
29
- import { BUILTIN_QUESTION_CHARS, MAX_PACK_QUESTION_CHARS, questionChars, semanticPoliciesFromPacks } from "./semantic/pack-policies";
29
+ import { JEV_POLICIES_QUESTION_CHARS, MAX_PACK_QUESTION_CHARS, questionChars, semanticPoliciesFromPacks } from "./semantic/pack-policies";
30
30
  import {
31
31
  AmbiguousPackId,
32
32
  PACK_CHECKSUMS_ASSET,
@@ -484,19 +484,20 @@ async function build(rest: string[]): Promise<PackCliResult> {
484
484
  // the user's machine, in manifest order — a pack that enforces less than it
485
485
  // says, which is the failure this whole lane is built to avoid.
486
486
  //
487
- // A pack from outside FailproofAI is ADDED to the built-in checks, which every
488
- // machine spends the budget on first (`semanticPoliciesFromPacks`), so it gets
489
- // only what they leave.
487
+ // A pack from outside FailproofAI shares one request with FailproofAI's own
488
+ // checks wherever both are installed, and those spend the budget first
489
+ // (`semanticPoliciesFromPacks`), so it is held to what they leave.
490
490
  const questionCost = semantic.reduce((total, entry) => total + questionChars(entry), 0);
491
491
  const firstParty = isFirstPartyPack(packSource);
492
- const questionBudget = MAX_PACK_QUESTION_CHARS - (firstParty ? 0 : BUILTIN_QUESTION_CHARS);
492
+ const questionBudget = MAX_PACK_QUESTION_CHARS - (firstParty ? 0 : JEV_POLICIES_QUESTION_CHARS);
493
493
  if (questionCost > questionBudget) {
494
494
  return fail([
495
495
  `This pack's ${semantic.length} semantic policies compile to ${questionCost} characters of questions, ` +
496
496
  (firstParty
497
497
  ? `over the ${MAX_PACK_QUESTION_CHARS} one Jev request has room for.`
498
498
  : `over the ${questionBudget} a machine leaves a pack from outside FailproofAI: one Jev request has room ` +
499
- `for ${MAX_PACK_QUESTION_CHARS}, and the 16 built-in checks every machine asks take ${BUILTIN_QUESTION_CHARS} of it first.`),
499
+ `for ${MAX_PACK_QUESTION_CHARS}, and FailproofAI/jev-policies' 16 checks take ${JEV_POLICIES_QUESTION_CHARS} of it first ` +
500
+ `where both are installed.`),
500
501
  "Shorten the probe instructions and criteria, or ship fewer policies per pack.",
501
502
  ]);
502
503
  }
@@ -511,9 +512,9 @@ async function build(rest: string[]): Promise<PackCliResult> {
511
512
  // Judged against the reviewers the PACK SHIPS WITH, not this build's: a pack
512
513
  // that carries both tiers replaces the compiled semantic set on every machine
513
514
  // that installs it, so `reviewedBy: ["its-own-check"]` is exactly right and
514
- // the builtin list would call it a name "this build does not have". A pack
515
- // with no semantic entries still answers to the builtin set, which is what its
516
- // machines will be running.
515
+ // FailproofAI's names would call it a name "this build does not have". A pack
516
+ // with no semantic entries answers to FailproofAI's sixteen names, which is
517
+ // what `FailproofAI/jev-policies` brings to the machines that install both.
517
518
  const reviewers = semantic.length > 0 ? new Set(semantic.map((s) => s.name)) : undefined;
518
519
  const authorityProblems = hooks.flatMap((hook) => {
519
520
  const problem = authorityProblem({ authority: hook.authority, reviewedBy: hook.reviewedBy }, reviewers);
@@ -590,8 +591,8 @@ async function build(rest: string[]): Promise<PackCliResult> {
590
591
  //
591
592
  // `minCliVersion` and `semantic` follow the same rule, and for `semantic` it is
592
593
  // load-bearing rather than tidy: an EMPTY array would still be "a pack that
593
- // declares semantic entries" to a careless reader, and the replacement rule
594
- // turns that into "this pack replaced the compiled-in set with nothing".
594
+ // declares semantic entries" to a careless reader, which would count it as a
595
+ // pack giving Jev checks when it gives none.
595
596
  const manifest =
596
597
  JSON.stringify(
597
598
  {
@@ -631,7 +632,7 @@ async function build(rest: string[]): Promise<PackCliResult> {
631
632
  `(${questionCost} characters of questions), ` +
632
633
  (identity.effect === "observe"
633
634
  ? "not asked where it installs: Jev asks only the checks of packs that enforce."
634
- : `${firstParty ? "replacing" : "added to"} the built-in checks where it installs.`),
635
+ : "asked by Jev wherever it installs."),
635
636
  ]
636
637
  : []),
637
638
  ...(requiredCli ? [` Requires failproofai ${requiredCli} or newer.`] : []),
@@ -2651,17 +2652,17 @@ function semanticPhrase(count: number): string {
2651
2652
  }
2652
2653
 
2653
2654
  /**
2654
- * How a pack's Jev checks sit beside this build's, for add, show and the
2655
- * picker alike: a FailproofAI pack's replace them, anyone else's are added
2656
- * (`replacesBuiltinChecks`), and only where `jevPacks` lets the pack take part —
2657
- * never for an observe pack, only for its agents when scoped. One phrase, so
2658
- * the three cannot drift apart again.
2655
+ * Whether a pack's Jev checks are asked, for add, show and the picker alike:
2656
+ * only where `jevPacks` lets the pack take part — never for an observe pack,
2657
+ * only for its agents when scoped. The package ships no checks of its own, so
2658
+ * a pack's are the whole set, beside any other pack's. One phrase, so the
2659
+ * three cannot drift apart again.
2659
2660
  */
2660
- function besideBuiltinChecks(pack: { source?: string; effect?: PolicyEffect; clis?: string[] | null }): string {
2661
+ function howJevAsksChecks(pack: { source?: string; effect?: PolicyEffect; clis?: string[] | null }): string {
2661
2662
  if (jevPacks([{ effect: pack.effect ?? "enforce", clis: null }]).length === 0) {
2662
2663
  return "not asked: this pack only observes, and Jev asks only the checks of packs that enforce";
2663
2664
  }
2664
- const how = isFirstPartyPack(pack) ? "replacing this build's own set" : "added to this build's own checks";
2665
+ const how = "asked by Jev on every tool call they apply to";
2665
2666
  return pack.clis && pack.clis.length > 0 ? `${how}, for ${pack.clis.join(", ")} only` : how;
2666
2667
  }
2667
2668
 
@@ -2716,7 +2717,7 @@ async function pickFromSource(
2716
2717
  if (preview.semantic.length > 0) {
2717
2718
  io.stdout.write(
2718
2719
  `\n This pack also brings ${semanticPhrase(preview.semantic.length)} (not selectable), ` +
2719
- `${besideBuiltinChecks(preview)}.\n See: failproofai policies show ${source}\n\n`,
2720
+ `${howJevAsksChecks(preview)}.\n See: failproofai policies show ${source}\n\n`,
2720
2721
  );
2721
2722
  }
2722
2723
  const picked = await multiSelect<string>({
@@ -2851,7 +2852,7 @@ async function add(rest: string[]): Promise<PackCliResult> {
2851
2852
  // the half somebody installed did nothing and nothing said so.
2852
2853
  if (result.semantic > 0) {
2853
2854
  lines.push(
2854
- ` ${semanticPhrase(result.semantic)}, ${besideBuiltinChecks(result)}. ` +
2855
+ ` ${semanticPhrase(result.semantic)}, ${howJevAsksChecks(result)}. ` +
2855
2856
  "They apply only where you configured Jev (`failproofai jev status`).",
2856
2857
  );
2857
2858
  }
@@ -3133,7 +3134,7 @@ function relativeAge(iso: string): string {
3133
3134
  *
3134
3135
  * Judged with `resolvePolicyAuthority` against the pack's OWN check names,
3135
3136
  * because that is the rule the installing machine applies: a pack declaring
3136
- * semantic entries replaces the compiled-in set (`effectiveReviewerNames`), so
3137
+ * semantic entries supplies the only checks it can name (`effectiveReviewerNames`), so
3137
3138
  * its `reviewedBy` may name only its own checks, and a declaration that names
3138
3139
  * anything else — or one sitting under `authority: "hard"`, which a manifest may
3139
3140
  * carry because the two fields are parsed independently — registers HARD. A
@@ -3247,7 +3248,7 @@ export function jevChecksSection(
3247
3248
  "",
3248
3249
  ...note(
3249
3250
  "Nothing toggles them: `--policy` cannot name one and `failproofai policies` never lists them. " +
3250
- `They arrive whole, ${besideBuiltinChecks(pack)}.`,
3251
+ `They arrive whole, ${howJevAsksChecks(pack)}.`,
3251
3252
  opts,
3252
3253
  ),
3253
3254
  ...note(
@@ -152,8 +152,8 @@ export interface InstalledPackRecord {
152
152
  *
153
153
  * `unknown` like `policies`, and optional like it is not: a pack published
154
154
  * before this field existed carries none, and every one of them must keep
155
- * parsing. A pack that declares at least one REPLACES the compiled-in
156
- * semantic set wholesale — see `semantic/pack-policies.ts`.
155
+ * parsing. The package ships no Jev checks, so these are the only ones a
156
+ * machine asks — see `semantic/pack-policies.ts`.
157
157
  */
158
158
  semantic?: unknown;
159
159
  /**
@@ -339,6 +339,29 @@ export function hasInstalledPacks(): boolean {
339
339
  }
340
340
  }
341
341
 
342
+ /**
343
+ * Whether an installed pack carries regex policies — the question the
344
+ * migration shim and `policies add <name>` actually mean to ask.
345
+ *
346
+ * `hasInstalledPacks` is the wrong question for them since the package stopped
347
+ * shipping Jev's checks: `FailproofAI/jev-policies` is now the normal way to
348
+ * turn Jev on, and it carries no regex policies. Counting it as "a pack is
349
+ * installed" switched off a legacy machine's `enabledPolicies` and sent a later
350
+ * `policies add block-rm-rf` to a pack that cannot enable it — both silently.
351
+ */
352
+ export function hasInstalledRegexPacks(): boolean {
353
+ try {
354
+ const raw = JSON.parse(readFileSync(installedFilePath(), "utf8")) as { packs?: unknown };
355
+ if (!Array.isArray(raw.packs)) return false;
356
+ return raw.packs.some(
357
+ (p) => !!p && typeof p === "object" && Array.isArray((p as { policies?: unknown }).policies)
358
+ && ((p as { policies: unknown[] }).policies.length > 0),
359
+ );
360
+ } catch {
361
+ return false;
362
+ }
363
+ }
364
+
342
365
  export function installedFilePath(): string {
343
366
  return process.env.FAILPROOFAI_PACK_DIR
344
367
  ? resolve(process.env.FAILPROOFAI_PACK_DIR, "installed.json")
@@ -1103,8 +1103,8 @@ export async function addPack(
1103
1103
  // installed did nothing.
1104
1104
  //
1105
1105
  // Omitted when empty for the same reason the manifest omits it: an empty
1106
- // array reads as "this pack declares semantic entries", and the replacement
1107
- // rule would then have it replace the compiled-in set with nothing.
1106
+ // array reads as "this pack declares semantic entries" — a pack giving Jev
1107
+ // checks when it gives none.
1108
1108
  ...(fetched.semantic.length > 0 ? { semantic: fetched.semantic } : {}),
1109
1109
  // Recorded so the READER re-checks it. This CLI has already satisfied it or
1110
1110
  // refused the install, but the record outlives this CLI: a downgrade, or a
@@ -10,7 +10,9 @@
10
10
  *
11
11
  * - `hard` is the default and the answer to anything unclear. Absent, a value
12
12
  * that is not one of the two, a `reviewedBy` that is empty or malformed or
13
- * names a check this build does not have, or an `alwaysOn` policy: all hard.
13
+ * names a check no installed pack declares, or an `alwaysOn` policy: all hard.
14
+ * With no pack declaring Jev checks there are no reviewers at all, and every
15
+ * policy is hard.
14
16
  * - `reviewable` means Jev may clear the policy's verdict — and only through the
15
17
  * semantic policies it names, every one of which must have been asked.
16
18
  *
@@ -55,16 +57,23 @@ export interface ResolvedAuthority {
55
57
  }
56
58
 
57
59
  /**
58
- * The names `reviewedBy` may use: the semantic policies in
59
- * `src/hooks/semantic/policies.ts`. Not the probes (`INJECTION_PROBE`,
60
+ * The names of the sixteen Jev checks FailproofAI publishes in the
61
+ * `FailproofAI/jev-policies` pack. Not the probes (`INJECTION_PROBE`,
60
62
  * `SCOPE_PROBE`, the task probes) — those are inputs to Jev's decision, not
61
63
  * checks a regex verdict can be cleared by.
62
64
  *
63
- * Written out rather than read off `SEMANTIC_POLICIES`, and pinned to it by
64
- * `policy-authority.test.ts`. The registry imports this module, so a runtime
65
- * import of the semantic policies would load all sixteen of Jev's prompts on
66
- * every hook event of a machine that never configured Jev, and bundle them into
67
- * every pack artifact that registers a policy.
65
+ * Names only: the package ships none of the checks themselves, and this list is
66
+ * NOT a set of reviewers any machine has. It is used for two things:
67
+ *
68
+ * - **Reserved names.** Declared by a pack not installed from a FailproofAI
69
+ * repository, one of these is void (`isReservedClaim`), so a third party
70
+ * cannot become the question that clears the core pack's policies.
71
+ * - **Build-time vocabulary.** The core pack (`scripts/build-policy-pack.mjs`)
72
+ * and a regex-only pack being published name these checks in `reviewedBy`
73
+ * while carrying none of them; they live in `FailproofAI/jev-policies`.
74
+ *
75
+ * Pinned to the reference copy of that pack (`__tests__/fixtures/jev-policies.ts`)
76
+ * by `policy-authority.test.ts`.
68
77
  */
69
78
  export const SEMANTIC_POLICY_NAMES = [
70
79
  "destructive-deletion",
@@ -85,17 +94,16 @@ export const SEMANTIC_POLICY_NAMES = [
85
94
  "external-data-egress",
86
95
  ] as const;
87
96
 
97
+ /** {@link SEMANTIC_POLICY_NAMES} as a set. Reserved names and build-time vocabulary — never a machine's live reviewers. */
98
+ export const SEMANTIC_REVIEWER_NAMES: ReadonlySet<string> = new Set(SEMANTIC_POLICY_NAMES);
99
+
88
100
  /**
89
- * The compiled-in reviewer set, and the DEFAULT rather than the only one.
90
- *
91
- * A pack that declares its own `semantic` entries replaces
92
- * `SEMANTIC_POLICIES` wholesale on the machine that installed it, so the names
93
- * a `reviewedBy` may use there are the pack's. Callers that know which set is
94
- * live pass it (`effectiveReviewerNames()` in `effective-reviewers.ts`, which reads
95
- * the manifest and imports nothing from `semantic/`); everyone else gets this
96
- * one, which is what a machine with no pack runs.
101
+ * The reviewer set of a machine with no installed pack declaring Jev checks —
102
+ * the vanilla install — and the default wherever a caller does not say which
103
+ * set is live. Empty: with nothing to ask, nothing can clear, and every
104
+ * `reviewable` declaration registers `hard`.
97
105
  */
98
- export const SEMANTIC_REVIEWER_NAMES: ReadonlySet<string> = new Set(SEMANTIC_POLICY_NAMES);
106
+ export const NO_REVIEWERS: ReadonlySet<string> = new Set<string>();
99
107
 
100
108
  const isName = (n: unknown): n is string => typeof n === "string" && n.length > 0;
101
109
 
@@ -103,7 +111,7 @@ const isName = (n: unknown): n is string => typeof n === "string" && n.length >
103
111
  * Judge one declaration.
104
112
  *
105
113
  * Stricter than `effectiveAuthority`, which is the §7 contract and needs only
106
- * one usable name: here EVERY entry must be a semantic policy this build has,
114
+ * one usable name: here EVERY entry must be a check this machine can ask,
107
115
  * and anything else makes the whole declaration hard rather than being dropped.
108
116
  * `reviewedBy` is a conjunction, so dropping a name the author wrote — a typo, a
109
117
  * stray `7` — would let Jev clear the policy on fewer checks than they asked
@@ -114,16 +122,23 @@ const isName = (n: unknown): n is string => typeof n === "string" && n.length >
114
122
  * What this returns is what `registerPolicy` stores, so a registered policy's
115
123
  * `reviewedBy` is always clean and the two functions agree on it.
116
124
  *
125
+ * With NO known reviewers — no installed pack declares a Jev check — a
126
+ * well-formed `reviewable` resolves `hard` WITHOUT a `downgraded` reason
127
+ * (unless a name it uses is contested between packs, which is still said). It is
128
+ * not a declaration going wrong but the machine having no Jev checks, which
129
+ * `jev status` and the dashboard say once; a warning per policy per hook event
130
+ * would say it fifteen times on every tool call of a core-pack machine.
131
+ *
117
132
  * @param knownReviewers - the semantic policies that CAN be asked on this
118
- * machine. Defaults to the compiled-in set, which is what runs until a pack
119
- * ships its own; see {@link SEMANTIC_REVIEWER_NAMES}. It is a parameter rather
120
- * than a lookup because this module is imported by the registry, and reading
121
- * which set is live means reading a file — a cost registration is willing to
122
- * pay once and this judgement must not pay per call.
133
+ * machine (`effectiveReviewerNames()` on the hook path). Defaults to
134
+ * {@link NO_REVIEWERS}, so a caller that does not say is fail-safe. It is a
135
+ * parameter rather than a lookup because this module is imported by the
136
+ * registry, and reading which set is live means reading a file — a cost
137
+ * registration is willing to pay once and this judgement must not pay per call.
123
138
  */
124
139
  export function resolvePolicyAuthority(
125
140
  decl: AuthorityDeclaration | undefined,
126
- knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
141
+ knownReviewers: ReadonlySet<string> = NO_REVIEWERS,
127
142
  /** Names left out of `knownReviewers` because packs declare them differently, with those packs. */
128
143
  contested?: ReadonlyMap<string, string[]>,
129
144
  ): ResolvedAuthority {
@@ -137,6 +152,8 @@ export function resolvePolicyAuthority(
137
152
  return { authority: "hard", downgraded: "reviewedBy is not a list of semantic policy names" };
138
153
  }
139
154
  const unknown = names.filter((n) => !knownReviewers.has(n));
155
+ // No checks at all, and no contest to explain: quietly hard (see above).
156
+ if (knownReviewers.size === 0 && !unknown.some((n) => contested?.has(n))) return { authority: "hard" };
140
157
  if (unknown.length > 0) {
141
158
  return { authority: "hard", downgraded: `reviewedBy names ${unknown.map((n) => whyUnknown(n, knownReviewers, contested)).join("; ")}` };
142
159
  }
@@ -144,8 +161,8 @@ export function resolvePolicyAuthority(
144
161
  }
145
162
 
146
163
  /**
147
- * The rule that kept one name out. "Not in this build" is only true of the
148
- * compiled-in set: a pack's own checks, or a name two packs disagree on, is a
164
+ * The rule that kept one name out. "Not in this build" is only true of
165
+ * FailproofAI's own names, judged at build or publish time: a pack's own checks, or a name two packs disagree on, is a
149
166
  * different reason, and the author reading it has a different fix.
150
167
  */
151
168
  function whyUnknown(name: string, known: ReadonlySet<string>, contested?: ReadonlyMap<string, string[]>): string {
@@ -205,9 +222,11 @@ export function authorityProblem(
205
222
  decl: AuthorityDeclaration,
206
223
  /**
207
224
  * The reviewers the pack being built will SHIP WITH — its own `semantic`
208
- * entries when it declares any, this build's set otherwise. A pack that
209
- * carries both halves of the two-tier set names its own checks, and refusing
210
- * that would make the feature unpublishable by the tool that implements it.
225
+ * entries when it declares any, FailproofAI's sixteen names otherwise (a
226
+ * regex-only pack names checks that ship in `FailproofAI/jev-policies`). A
227
+ * pack that carries both halves of the two-tier set names its own checks, and
228
+ * refusing that would make the feature unpublishable by the tool that
229
+ * implements it.
211
230
  */
212
231
  knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
213
232
  ): string | undefined {
@@ -283,13 +302,13 @@ export function manifestAuthority(
283
302
  *
284
303
  * @param knownReviewers - the checks that can be asked on this machine. Callers
285
304
  * that merge what will be REGISTERED must pass `effectiveReviewerNames()`;
286
- * the default is this build's compiled-in set, which is what a machine with no
287
- * pack runs.
305
+ * the default is {@link NO_REVIEWERS}, which is what a machine with no pack
306
+ * declaring Jev checks has.
288
307
  */
289
308
  export function withMergedAuthority<T extends AuthorityFields>(
290
309
  record: T,
291
310
  declarations: ReadonlyArray<AuthorityFields>,
292
- knownReviewers: ReadonlySet<string> = SEMANTIC_REVIEWER_NAMES,
311
+ knownReviewers: ReadonlySet<string> = NO_REVIEWERS,
293
312
  ): { merged: T; overruled: boolean; refused?: string } {
294
313
  const resolved = declarations.map((d) => resolvePolicyAuthority(d, knownReviewers));
295
314
  const allReviewable = resolved.length > 0 && resolved.every((r) => r.authority === "reviewable");
@@ -24,7 +24,7 @@ import {
24
24
  type JevActivityFields,
25
25
  type JevReview,
26
26
  type RegexVerdict,
27
- type ShadowVerdict,
27
+ type ObserveVerdict,
28
28
  type TwoTierReview,
29
29
  } from "./semantic/combine";
30
30
  // The code, not a copy of the string: the log line below turns on it, and a
@@ -62,8 +62,8 @@ export interface EvaluationResult {
62
62
  decidedByJev: boolean;
63
63
  /** The pack a deciding Jev check came from; only with `decidedByJev`. */
64
64
  jevOrigin?: { packId: string; packVersion?: string };
65
- /** Shadow mode: Jev's own deny/instruct, recorded as a "would have" (see `ShadowVerdict`). */
66
- shadowVerdict?: ShadowVerdict;
65
+ /** Observe mode: Jev's own deny/instruct, recorded as a "would have" (see `ObserveVerdict`). */
66
+ observeVerdict?: ObserveVerdict;
67
67
  };
68
68
  }
69
69
 
@@ -219,7 +219,7 @@ export async function evaluatePolicies(
219
219
  }
220
220
  const combined = combineTwoTier(collected.verdicts, review, twoTier.mode);
221
221
  if (combined.cleared.length > 0) {
222
- hookLogInfo(`jev ${twoTier.mode === "shadow" ? "would clear" : "cleared"}: ${combined.cleared.join(", ")}`);
222
+ hookLogInfo(`jev ${twoTier.mode === "observe" ? "would clear" : "cleared"}: ${combined.cleared.join(", ")}`);
223
223
  }
224
224
  if (combined.activity.evaluator === "jev-fallback") {
225
225
  // Info, not warn: during an outage this is every gated call, and warn-level
@@ -251,7 +251,7 @@ export async function evaluatePolicies(
251
251
  activity: combined.activity,
252
252
  decidedByJev: combined.decidedByJev,
253
253
  ...(combined.decidedByJev && review.kind === "answered" && review.origin ? { jevOrigin: review.origin } : {}),
254
- ...(combined.shadowVerdict ? { shadowVerdict: combined.shadowVerdict } : {}),
254
+ ...(combined.observeVerdict ? { observeVerdict: combined.observeVerdict } : {}),
255
255
  },
256
256
  };
257
257
  }
@@ -73,13 +73,11 @@ export function registerPolicy(
73
73
  const canonical = normalizePolicyName(name);
74
74
  const registry = getRegistry();
75
75
  const idx = registry.findIndex((p) => p.name === canonical);
76
- // Judged against the reviewers this MACHINE can ask, not against the ones this
77
- // build compiled in. A pack that ships its own `semantic` set replaces the
78
- // compiled one, so its policies name checks that exist here and nowhere in
79
- // `SEMANTIC_POLICY_NAMES` — and judging them by the builtin list would
80
- // downgrade the whole rewritten set to `hard` while reporting nothing but a
81
- // warning. `effectiveReviewerNames` reads the manifest — already where a
82
- // pack's `reviewedBy` itself comes from — once per registration pass.
76
+ // Judged against the reviewers this MACHINE can ask: the checks its installed
77
+ // packs declare, and none when no pack declares any (the package ships no
78
+ // Jev checks), in which case every policy registers `hard`.
79
+ // `effectiveReviewerNames` reads the manifest — already where a pack's
80
+ // `reviewedBy` itself comes from — once per registration pass.
83
81
  const authority = meta ? resolvePolicyAuthority(meta, effectiveReviewerNames()) : undefined;
84
82
  const entry: RegisteredPolicy = {
85
83
  name: canonical, description, fn, match, priority,
@@ -62,7 +62,7 @@ import { discoverPolicyFiles } from "./custom-hooks-loader";
62
62
  import { customPoliciesDir } from "./fp-home";
63
63
  import { configuredCustomPolicyPaths, findProjectConfigDir, readMergedHooksConfig } from "./hooks-config";
64
64
  import { hasInstalledPacks, readInstalledPacks } from "./pack-manifest";
65
- import { resolvePolicyAuthority, SEMANTIC_REVIEWER_NAMES } from "./policy-authority";
65
+ import { resolvePolicyAuthority } from "./policy-authority";
66
66
  import { POLICY_CATALOG } from "./policy-catalog";
67
67
  import { normalizePolicyName } from "./policy-registry";
68
68
  import type { HooksConfig } from "./policy-types";
@@ -87,11 +87,23 @@ export interface ReviewableCoverage {
87
87
  * user convention files — whose policies are not in the counts above.
88
88
  */
89
89
  customFiles: number;
90
+ /**
91
+ * Jev checks the installed packs give it to ask. Zero on a machine with no
92
+ * pack declaring any — the vanilla install — and then Jev is never called.
93
+ */
94
+ jevChecks: number;
90
95
  }
91
96
 
92
97
  /** The command that replaces a pack with one built by this release. */
93
98
  export const RETAKE_PACK_COMMAND = "failproofai policies add FailproofAI/policies";
94
99
 
100
+ /** The command that gives Jev its checks. The package ships none. */
101
+ export const JEV_POLICIES_ADD_COMMAND = "failproofai policies add FailproofAI/jev-policies";
102
+
103
+ /** Said wherever Jev is configured but has nothing to ask. Kept short: it is a status line. */
104
+ export const NO_JEV_CHECKS_PROBLEM =
105
+ `Jev has no checks installed, so it asks nothing and clears nothing. To enable it: \`${JEV_POLICIES_ADD_COMMAND}\`.`;
106
+
95
107
  /**
96
108
  * Count a policy set by the authority it would REGISTER with —
97
109
  * `resolvePolicyAuthority`, the rule `registerPolicy` applies — so this cannot
@@ -112,11 +124,9 @@ export const RETAKE_PACK_COMMAND = "failproofai policies add FailproofAI/policie
112
124
  export function countReviewable(
113
125
  policies: Iterable<AuthorityRecord>,
114
126
  /**
115
- * The semantic checks that can be asked on this machine. Defaults to the
116
- * compiled-in set; `surveyReviewableCoverage` passes the pack's when one
117
- * declares its own, because otherwise this diagnostic reports "0 of 11
118
- * reviewable" on exactly the machines the feature was built for — the ones
119
- * running a pack that carries both tiers.
127
+ * The semantic checks that can be asked on this machine — the ones installed
128
+ * packs declare. Defaults to none, which is what a machine with no such pack
129
+ * has: nothing is reviewable there.
120
130
  */
121
131
  knownReviewers?: ReadonlySet<string>,
122
132
  ): {
@@ -169,10 +179,11 @@ export function surveyReviewableCoverage(cwd?: string): ReviewableCoverage {
169
179
  // hook path's manifest-only `reviewerNamesFor` cannot see. Anything else and
170
180
  // the panel and `jev status` promise a clear that cannot happen.
171
181
  const asked = semanticPoliciesFromPacks(jevPacks(packs));
172
- reviewers = asked.fromPack ? new Set(asked.policies.map((p) => p.name)) : SEMANTIC_REVIEWER_NAMES;
182
+ reviewers = new Set(asked.policies.map((p) => p.name));
173
183
  } catch {
174
- // An unreadable manifest enforces nothing; `readInstalledPacks` already
175
- // reports that to the hook log on the path that cares.
184
+ // An unreadable manifest enforces nothing and gives Jev nothing to ask;
185
+ // `readInstalledPacks` already reports that to the hook log on the path
186
+ // that cares.
176
187
  }
177
188
 
178
189
  let config: HooksConfig;
@@ -212,7 +223,7 @@ export function surveyReviewableCoverage(cwd?: string): ReviewableCoverage {
212
223
  customFiles = 0;
213
224
  }
214
225
 
215
- return { ...countReviewable(records, reviewers), customFiles };
226
+ return { ...countReviewable(records, reviewers), customFiles, jevChecks: reviewers?.size ?? 0 };
216
227
  }
217
228
 
218
229
  /**
@@ -244,8 +255,13 @@ export function reviewableSummary(coverage: ReviewableCoverage): string {
244
255
  * Nothing is diagnosed for an empty policy set: there is no clear to lose, and
245
256
  * an authority warning to someone who enforces nothing answers a question they
246
257
  * did not ask.
258
+ *
259
+ * Except the one thing that comes first: no installed pack gives Jev any checks.
260
+ * Then Jev asks nothing whatever the policy set is, and the fix is to install
261
+ * them, not to re-mark anything.
247
262
  */
248
263
  export function reviewableProblem(coverage: ReviewableCoverage): string | null {
264
+ if (coverage.jevChecks === 0) return NO_JEV_CHECKS_PROBLEM;
249
265
  // Policies from the user's own files were not counted and may be reviewable,
250
266
  // so "never" cannot be said honestly; the summary already says what was skipped.
251
267
  if (coverage.enabled === 0 || coverage.reviewable > 0 || coverage.customFiles > 0) return null;
@@ -46,9 +46,9 @@ export interface RegisteredPolicy {
46
46
  /** Whether Jev may clear this policy's deny/instruct; see {@link effectiveAuthority}. */
47
47
  authority?: PolicyAuthority;
48
48
  /**
49
- * The semantic policies (`src/hooks/semantic/policies.ts`) that must all be
50
- * asked, and each clear (see {@link PolicyAuthority}), before Jev clears this
51
- * policy.
49
+ * The Jev checks (declared by an installed pack — the package ships none)
50
+ * that must all be asked, and each clear (see {@link PolicyAuthority}),
51
+ * before Jev clears this policy.
52
52
  */
53
53
  reviewedBy?: string[];
54
54
  }
@@ -188,7 +188,7 @@ export interface SemanticProbeDeclaration {
188
188
  /**
189
189
  * A semantic (Jev) policy as its author DECLARES it — a question set, not code.
190
190
  *
191
- * The compiled-in equivalent is `SemanticPolicy` in `semantic/types.ts`, and
191
+ * The runtime form is `SemanticPolicy` in `semantic/types.ts`, and
192
192
  * the one difference is the whole reason both exist: there, `precondition` is a
193
193
  * function over the computed facts; here it is the NAME of one, because a
194
194
  * declaration has to survive a trip through a JSON manifest and because a