approval-md 0.2.0 → 0.3.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 (235) hide show
  1. package/README.md +63 -24
  2. package/SPEC.md +57 -11
  3. package/dist/src/channels/contract.d.ts +34 -1
  4. package/dist/src/channels/contract.js +200 -7
  5. package/dist/src/channels/contract.js.map +1 -1
  6. package/dist/src/channels/telegram.d.ts +123 -11
  7. package/dist/src/channels/telegram.js +218 -23
  8. package/dist/src/channels/telegram.js.map +1 -1
  9. package/dist/src/channels/web.d.ts +9 -0
  10. package/dist/src/channels/web.js +17 -0
  11. package/dist/src/channels/web.js.map +1 -1
  12. package/dist/src/cli/amend.js +214 -30
  13. package/dist/src/cli/amend.js.map +1 -1
  14. package/dist/src/cli/attest.d.ts +9 -0
  15. package/dist/src/cli/attest.js +134 -7
  16. package/dist/src/cli/attest.js.map +1 -1
  17. package/dist/src/cli/channel-telegram.d.ts +99 -26
  18. package/dist/src/cli/channel-telegram.js +311 -13
  19. package/dist/src/cli/channel-telegram.js.map +1 -1
  20. package/dist/src/cli/channel.d.ts +9 -0
  21. package/dist/src/cli/channel.js +9 -0
  22. package/dist/src/cli/channel.js.map +1 -1
  23. package/dist/src/cli/codex-bridge.d.ts +819 -0
  24. package/dist/src/cli/codex-bridge.js +1607 -0
  25. package/dist/src/cli/codex-bridge.js.map +1 -0
  26. package/dist/src/cli/codex.d.ts +1 -1
  27. package/dist/src/cli/codex.js +304 -7
  28. package/dist/src/cli/codex.js.map +1 -1
  29. package/dist/src/cli/daemon.js +4 -1
  30. package/dist/src/cli/daemon.js.map +1 -1
  31. package/dist/src/cli/doctor.js +467 -12
  32. package/dist/src/cli/doctor.js.map +1 -1
  33. package/dist/src/cli/execute.js +25 -2
  34. package/dist/src/cli/execute.js.map +1 -1
  35. package/dist/src/cli/help.d.ts +6 -2
  36. package/dist/src/cli/help.js +165 -60
  37. package/dist/src/cli/help.js.map +1 -1
  38. package/dist/src/cli/hook-codex.d.ts +49 -1
  39. package/dist/src/cli/hook-codex.js +60 -1
  40. package/dist/src/cli/hook-codex.js.map +1 -1
  41. package/dist/src/cli/hook.d.ts +459 -3
  42. package/dist/src/cli/hook.js +1062 -114
  43. package/dist/src/cli/hook.js.map +1 -1
  44. package/dist/src/cli/import.js +1 -1
  45. package/dist/src/cli/import.js.map +1 -1
  46. package/dist/src/cli/main.js +5 -3
  47. package/dist/src/cli/main.js.map +1 -1
  48. package/dist/src/cli/policy-apply.d.ts +195 -0
  49. package/dist/src/cli/policy-apply.js +573 -0
  50. package/dist/src/cli/policy-apply.js.map +1 -0
  51. package/dist/src/cli/policy.js +14 -1
  52. package/dist/src/cli/policy.js.map +1 -1
  53. package/dist/src/cli/preflight.d.ts +151 -13
  54. package/dist/src/cli/preflight.js +398 -41
  55. package/dist/src/cli/preflight.js.map +1 -1
  56. package/dist/src/cli/sandbox.js +17 -1
  57. package/dist/src/cli/sandbox.js.map +1 -1
  58. package/dist/src/cli/scaffold.d.ts +1 -1
  59. package/dist/src/cli/scaffold.js +1 -1
  60. package/dist/src/cli/setup-channel.d.ts +9 -0
  61. package/dist/src/cli/setup-channel.js +28 -1
  62. package/dist/src/cli/setup-channel.js.map +1 -1
  63. package/dist/src/cli/setup-common.d.ts +3 -1
  64. package/dist/src/cli/setup-common.js +3 -2
  65. package/dist/src/cli/setup-common.js.map +1 -1
  66. package/dist/src/cli/setup.d.ts +2 -0
  67. package/dist/src/cli/setup.js +94 -2
  68. package/dist/src/cli/setup.js.map +1 -1
  69. package/dist/src/cli/up.js +115 -51
  70. package/dist/src/cli/up.js.map +1 -1
  71. package/dist/src/cli/values.js +3 -4
  72. package/dist/src/cli/values.js.map +1 -1
  73. package/dist/src/cli/verb-registry.js +174 -9
  74. package/dist/src/cli/verb-registry.js.map +1 -1
  75. package/dist/src/cli/wordmark.d.ts +2 -2
  76. package/dist/src/cli/wordmark.js +2 -2
  77. package/dist/src/codex/broker.d.ts +229 -0
  78. package/dist/src/codex/broker.js +548 -0
  79. package/dist/src/codex/broker.js.map +1 -0
  80. package/dist/src/codex/runner.d.ts +178 -0
  81. package/dist/src/codex/runner.js +231 -0
  82. package/dist/src/codex/runner.js.map +1 -0
  83. package/dist/src/codex/serve.d.ts +56 -0
  84. package/dist/src/codex/serve.js +98 -0
  85. package/dist/src/codex/serve.js.map +1 -0
  86. package/dist/src/codex/workspace-commit.d.ts +219 -0
  87. package/dist/src/codex/workspace-commit.js +549 -0
  88. package/dist/src/codex/workspace-commit.js.map +1 -0
  89. package/dist/src/core/advance-cycle.d.ts +51 -0
  90. package/dist/src/core/advance-cycle.js +66 -2
  91. package/dist/src/core/advance-cycle.js.map +1 -1
  92. package/dist/src/core/agents-md.d.ts +20 -18
  93. package/dist/src/core/agents-md.js +33 -31
  94. package/dist/src/core/agents-md.js.map +1 -1
  95. package/dist/src/core/attest.d.ts +215 -0
  96. package/dist/src/core/attest.js +317 -7
  97. package/dist/src/core/attest.js.map +1 -1
  98. package/dist/src/core/audit.d.ts +18 -0
  99. package/dist/src/core/audit.js +13 -0
  100. package/dist/src/core/audit.js.map +1 -1
  101. package/dist/src/core/channel-owner.d.ts +213 -0
  102. package/dist/src/core/channel-owner.js +358 -0
  103. package/dist/src/core/channel-owner.js.map +1 -0
  104. package/dist/src/core/command-class.d.ts +154 -0
  105. package/dist/src/core/command-class.js +673 -20
  106. package/dist/src/core/command-class.js.map +1 -1
  107. package/dist/src/core/commit-guard.d.ts +272 -0
  108. package/dist/src/core/commit-guard.js +424 -0
  109. package/dist/src/core/commit-guard.js.map +1 -0
  110. package/dist/src/core/daemon-actor.d.ts +45 -0
  111. package/dist/src/core/daemon-actor.js +54 -0
  112. package/dist/src/core/daemon-actor.js.map +1 -0
  113. package/dist/src/core/dark-session.d.ts +109 -8
  114. package/dist/src/core/dark-session.js +266 -82
  115. package/dist/src/core/dark-session.js.map +1 -1
  116. package/dist/src/core/decision-refusal.d.ts +23 -2
  117. package/dist/src/core/decision-refusal.js +24 -2
  118. package/dist/src/core/decision-refusal.js.map +1 -1
  119. package/dist/src/core/env-file.d.ts +5 -0
  120. package/dist/src/core/env-file.js +60 -1
  121. package/dist/src/core/env-file.js.map +1 -1
  122. package/dist/src/core/execute.d.ts +15 -2
  123. package/dist/src/core/execute.js +15 -2
  124. package/dist/src/core/execute.js.map +1 -1
  125. package/dist/src/core/gate.d.ts +86 -1
  126. package/dist/src/core/gate.js +81 -1
  127. package/dist/src/core/gate.js.map +1 -1
  128. package/dist/src/core/gesture-refusal.d.ts +166 -0
  129. package/dist/src/core/gesture-refusal.js +188 -0
  130. package/dist/src/core/gesture-refusal.js.map +1 -0
  131. package/dist/src/core/harness-version.d.ts +1 -1
  132. package/dist/src/core/harness-version.js +3 -1
  133. package/dist/src/core/harness-version.js.map +1 -1
  134. package/dist/src/core/instance.d.ts +59 -2
  135. package/dist/src/core/instance.js +113 -0
  136. package/dist/src/core/instance.js.map +1 -1
  137. package/dist/src/core/log.d.ts +39 -1
  138. package/dist/src/core/log.js.map +1 -1
  139. package/dist/src/core/policy-explain.d.ts +10 -0
  140. package/dist/src/core/policy-explain.js +32 -0
  141. package/dist/src/core/policy-explain.js.map +1 -1
  142. package/dist/src/core/policy-load.d.ts +41 -1
  143. package/dist/src/core/policy-load.js +21 -3
  144. package/dist/src/core/policy-load.js.map +1 -1
  145. package/dist/src/core/policy-match.d.ts +43 -0
  146. package/dist/src/core/policy-match.js +52 -0
  147. package/dist/src/core/policy-match.js.map +1 -1
  148. package/dist/src/core/policy-proposal.d.ts +52 -0
  149. package/dist/src/core/policy-proposal.js +102 -2
  150. package/dist/src/core/policy-proposal.js.map +1 -1
  151. package/dist/src/core/protected-path-guard.d.ts +117 -4
  152. package/dist/src/core/protected-path-guard.js +362 -48
  153. package/dist/src/core/protected-path-guard.js.map +1 -1
  154. package/dist/src/core/question-preempted.d.ts +141 -0
  155. package/dist/src/core/question-preempted.js +152 -0
  156. package/dist/src/core/question-preempted.js.map +1 -0
  157. package/dist/src/core/read-scope.d.ts +172 -0
  158. package/dist/src/core/read-scope.js +252 -0
  159. package/dist/src/core/read-scope.js.map +1 -0
  160. package/dist/src/core/sandbox.d.ts +81 -0
  161. package/dist/src/core/sandbox.js +190 -1
  162. package/dist/src/core/sandbox.js.map +1 -1
  163. package/dist/src/core/sender-identity.d.ts +476 -0
  164. package/dist/src/core/sender-identity.js +572 -0
  165. package/dist/src/core/sender-identity.js.map +1 -0
  166. package/dist/src/core/shlex.d.ts +102 -0
  167. package/dist/src/core/shlex.js +159 -0
  168. package/dist/src/core/shlex.js.map +1 -0
  169. package/dist/src/core/values.d.ts +18 -8
  170. package/dist/src/core/values.js +36 -1
  171. package/dist/src/core/values.js.map +1 -1
  172. package/dist/src/daemon/advance.d.ts +10 -0
  173. package/dist/src/daemon/advance.js +25 -4
  174. package/dist/src/daemon/advance.js.map +1 -1
  175. package/dist/src/daemon/daemon.js +9 -0
  176. package/dist/src/daemon/daemon.js.map +1 -1
  177. package/dist/src/daemon/git-evidence.d.ts +2 -2
  178. package/dist/src/daemon/git-evidence.js +1 -1
  179. package/dist/src/mcp/server.js +8 -0
  180. package/dist/src/mcp/server.js.map +1 -1
  181. package/docs/cli-reference.md +932 -32
  182. package/docs/codex-enforced-session.md +75 -2
  183. package/docs/codex-workspace-broker.md +118 -0
  184. package/package.json +3 -1
  185. package/schema/event.schema.json +538 -9
  186. package/schema/fixtures/event/invalid/approval-granted-sender-hashed-false.json +20 -0
  187. package/schema/fixtures/event/invalid/approval-granted-sender-hashed-raw-id.json +20 -0
  188. package/schema/fixtures/event/invalid/audit-gesture-refused-human-actor.json +16 -0
  189. package/schema/fixtures/event/invalid/audit-gesture-refused-no-actor-no-sender.json +15 -0
  190. package/schema/fixtures/event/invalid/audit-gesture-refused-unknown-gesture.json +16 -0
  191. package/schema/fixtures/event/invalid/audit-question-preempted-agent-actor.json +16 -0
  192. package/schema/fixtures/event/invalid/audit-question-preempted-no-question-id.json +16 -0
  193. package/schema/fixtures/event/invalid/audit-question-preempted-unknown-source.json +15 -0
  194. package/schema/fixtures/event/invalid/gate-path-signed-off-absolute-path.json +14 -0
  195. package/schema/fixtures/event/invalid/gate-path-signed-off-agent-actor.json +14 -0
  196. package/schema/fixtures/event/invalid/gate-path-signed-off-missing-path.json +13 -0
  197. package/schema/fixtures/event/valid/approval-granted-sender-hashed.json +20 -0
  198. package/schema/fixtures/event/valid/audit-gesture-refused-review-note.json +21 -0
  199. package/schema/fixtures/event/valid/audit-gesture-refused-sender-key-unavailable.json +19 -0
  200. package/schema/fixtures/event/valid/audit-gesture-refused.json +19 -0
  201. package/schema/fixtures/event/valid/audit-question-preempted-no-verdict.json +16 -0
  202. package/schema/fixtures/event/valid/audit-question-preempted.json +20 -0
  203. package/schema/fixtures/event/valid/gate-path-signed-off.json +14 -0
  204. package/schema/fixtures/event/valid/harness-kind-claude-code.json +23 -0
  205. package/schema/fixtures/event/valid/harness-kind-codex.json +23 -0
  206. package/schema/fixtures/event/valid/harness-kind-cursor.json +23 -0
  207. package/schema/fixtures/event/valid/harness-kind-grok.json +23 -0
  208. package/schema/fixtures/event/valid/harness-kind-muse.json +23 -0
  209. package/schema/fixtures/policy/invalid/senders-half-keyed.json +20 -0
  210. package/schema/fixtures/policy/valid/canonical.json +1 -1
  211. package/schema/fixtures/policy/valid/senders-keyed.json +24 -0
  212. package/schema/fixtures/policy-md/valid/canonical.md +1 -1
  213. package/schema/fixtures/policy-md/valid/with-values.md +5 -7
  214. package/schema/fixtures/values/invalid/class-shaped.json +1 -1
  215. package/schema/fixtures/values/invalid/duplicate-entry.json +1 -1
  216. package/schema/fixtures/values/invalid/non-string-item.json +1 -1
  217. package/schema/fixtures/values/invalid/over-cap.json +1 -1
  218. package/schema/fixtures/values/invalid/unknown-key.json +1 -1
  219. package/schema/fixtures/values/invalid/version-float.json +1 -0
  220. package/schema/fixtures/values/invalid/version-integer.json +1 -0
  221. package/schema/fixtures/values/invalid/version-wrong-string.json +1 -0
  222. package/schema/fixtures/values/valid/empty-lists.json +2 -3
  223. package/schema/fixtures/values/valid/full.json +5 -7
  224. package/schema/fixtures/values/valid/minimal.json +1 -1
  225. package/schema/fixtures/values-md/invalid/schema-invalid.md +5 -3
  226. package/schema/fixtures/values-md/invalid/two-blocks.md +3 -3
  227. package/schema/fixtures/values-md/invalid/unterminated.md +2 -2
  228. package/schema/fixtures/values-md/invalid/version-1.md +69 -0
  229. package/schema/fixtures/values-md/invalid/version-unquoted.md +64 -0
  230. package/schema/fixtures/values-md/invalid/yaml-error.md +2 -2
  231. package/schema/fixtures/values-md/valid/absent.md +1 -1
  232. package/schema/fixtures/values-md/valid/with-values.md +5 -7
  233. package/schema/policy.schema.json +54 -2
  234. package/schema/values.schema.json +7 -11
  235. package/schema/fixtures/values/invalid/version-string.json +0 -1
@@ -32,6 +32,20 @@
32
32
  * Self-reported text is never read. The hook passes the command only; the
33
33
  * harness's `description` field is authored by the very agent being gated
34
34
  * (SPEC.md §11.1: self-reported fields never reduce scrutiny).
35
+ *
36
+ * Two imports, and both are pure in exactly the same way this file is: no disk,
37
+ * no clock, no environment, no dependencies.
38
+ *
39
+ * `core/read-scope.ts` (APRV-347) holds the read-side path arithmetic, so the
40
+ * hook and the policy explainer can ask the same questions this file asks, of
41
+ * the same table, rather than each growing a copy of it.
42
+ *
43
+ * `core/policy-match.ts` (APRV-354) is imported for ONE name, the
44
+ * `harness.launch.` prefix. The classifier emits the family and two enforcement
45
+ * paths refuse a member of it that no policy rule names, so the three have to
46
+ * agree on what the family is; a second spelling of the prefix would close one
47
+ * of those doors and leave the other open. The import is type-safe in the
48
+ * dependency sense as well: `policy-match.ts` itself imports only types.
35
49
  */
36
50
  /** Why a command could not be classified. Each denies; none is a soft failure. */
37
51
  export type ClassifierFailureCode = "unclassified" | "opaque" | "unparseable";
@@ -352,6 +366,26 @@ export declare const NON_SECRET_ENV_NAMES: readonly string[];
352
366
  * environment rather than of command text, and it must ask it the same way.
353
367
  */
354
368
  export declare function isSecretEnvName(name: string): boolean;
369
+ interface LexWord {
370
+ /** Literal text, quotes removed and backslash escapes applied. */
371
+ text: string;
372
+ /** True when any part of the word was quoted. */
373
+ quoted: boolean;
374
+ /** Inner text of each `$(…)` in this word, for recursive classification. */
375
+ substitutions: string[];
376
+ }
377
+ interface LexRedirect {
378
+ /** `>` and `>>` write; `<` reads. */
379
+ op: ">" | ">>" | "<";
380
+ target: LexWord;
381
+ }
382
+ interface LexSegment {
383
+ text: string;
384
+ words: LexWord[];
385
+ redirects: LexRedirect[];
386
+ /** Set when the segment contains a construct whose effect cannot be read. */
387
+ opaque: string | null;
388
+ }
355
389
  /**
356
390
  * Facts about the machine the command will run on, resolved by the CALLER
357
391
  * (APRV-267).
@@ -381,6 +415,38 @@ export interface ClassifierContext {
381
415
  * own: a path under a root still has to survive that second pass.
382
416
  */
383
417
  scratchRoots?: readonly string[];
418
+ /**
419
+ * Roots a read may stay inside: the gate root, the session scratchpad and the
420
+ * system temp root, plus whatever `read_scope.roots` added (APRV-347).
421
+ *
422
+ * The polarity is the OPPOSITE of `scratchRoots`, and the difference is worth
423
+ * stating. A scratch root LOOSENS a delete, so forgetting the field is safe
424
+ * by construction. A read root NARROWS a read, so forgetting the field would
425
+ * be safe in a different way — it leaves every read `read.shell`, exactly as
426
+ * this classifier answered before the field existed. An EMPTY array means the
427
+ * same thing as absent, and deliberately: read against no roots at all would
428
+ * make every read in the session a decision, which is a fail-closed answer
429
+ * nobody asked for and the one spelling a caller reaches by accident. A
430
+ * caller that means to scope reads passes roots.
431
+ *
432
+ * As with `scratchRoots`, this file only compares segments. The relative
433
+ * paths, the symlinks and the working directory are the hook's second pass,
434
+ * which can only ever tighten the answer reached here.
435
+ */
436
+ readRoots?: readonly string[];
437
+ /**
438
+ * May a login-shell wrapper be classified by the script it runs (APRV-380)?
439
+ *
440
+ * `true` by default, and `false` for exactly one caller: the classifier
441
+ * itself, recursing into an unwrapped script. That is what keeps the unwrap
442
+ * ONE LEVEL deep — a shell nested inside the script is the shape the
443
+ * {@link OPAQUE_BINS} position still covers, and it stays opaque.
444
+ *
445
+ * A caller that passes `false` gets the pre-APRV-380 answer, which is the
446
+ * strictly stricter one: every wrapper refuses. As with every other field
447
+ * here, forgetting it cannot loosen anything.
448
+ */
449
+ unwrapShell?: boolean;
384
450
  }
385
451
  /** Everything a refinement needs: the binary and the words that followed it. */
386
452
  interface RuleContext {
@@ -413,6 +479,7 @@ interface RuleContext {
413
479
  type Refinement = {
414
480
  class: string;
415
481
  rule: string;
482
+ path?: string;
416
483
  } | {
417
484
  opaque: string;
418
485
  };
@@ -435,6 +502,19 @@ export interface CommandRule {
435
502
  /** Flag-sensitive answer; falls back to `class` when it returns `null`. */
436
503
  refine?: (ctx: RuleContext) => Refinement | null;
437
504
  }
505
+ /**
506
+ * The suffix that marks a Muse model as training on what it is shown.
507
+ *
508
+ * Exported since APRV-350 so the hook adapter's contributor guard and this
509
+ * classifier's `harness.launch.muse` refinement test the SAME mark. Two
510
+ * spellings of "which models are unsafe" would drift, and the direction they
511
+ * drift in is the one where a launch is refused and a tool call is not.
512
+ */
513
+ export declare const CONTRIBUTOR_SUFFIX = "-contributor";
514
+ /** The rule id for a read whose ABSOLUTE target sits outside every root. */
515
+ export declare const READ_OUT_OF_SCOPE_RULE = "read-out-of-scope";
516
+ /** The rule id for a read target whose expansion the text cannot show. */
517
+ export declare const READ_UNREADABLE_TARGET_RULE = "read-unreadable-path";
438
518
  /**
439
519
  * The table.
440
520
  *
@@ -446,6 +526,42 @@ export interface CommandRule {
446
526
  * move the log file, introduced by SPEC §10.1's APRV-125 amendment.
447
527
  */
448
528
  export declare const COMMAND_RULES: readonly CommandRule[];
529
+ /**
530
+ * The script a LOGIN-SHELL WRAPPER runs, when the segment is exactly one
531
+ * (APRV-380), or `null`.
532
+ *
533
+ * ## Why this is not the second parser the table above refuses
534
+ *
535
+ * {@link OPAQUE_BINS} states the position this narrows: a second parser for the
536
+ * same text is a second answer waiting to disagree with the shell's. The hazard
537
+ * that names is reading shell text a SECOND WAY. This is not that. When the
538
+ * argv is exactly `[shell, -lc, script]` and nothing else, the script is the
539
+ * text a Claude Code `Bash` call hands this classifier directly, and what
540
+ * happens to it here is what happens to that: the same lexer, the same segment
541
+ * rules, the same table. No new parser is written, and the text is not read a
542
+ * second way — it is read the first way, by the only reader there is.
543
+ *
544
+ * ## The line, and it is exact
545
+ *
546
+ * Three words, no more: a known shell, one inline-script flag, one script. Any
547
+ * of these keeps the wrapper opaque, because each is a shape whose effect
548
+ * depends on something the argv alone does not say:
549
+ *
550
+ * - extra words (a script FILE, `--`, an option this rule does not model);
551
+ * - an assignment prefix, which changes the environment the script runs in;
552
+ * - a redirection on the wrapper, which is the outer shell's and not the
553
+ * script's;
554
+ * - a substitution in any of the three words, whose effect happens before the
555
+ * shell even starts;
556
+ * - a nested shell inside the script, refused by {@link ClassifierContext} when
557
+ * the recursion runs (the inner classification unwraps nothing).
558
+ *
559
+ * The BINDING does not move. `cli/hook.ts` binds the outer command and argv
560
+ * exactly as APRV-362 built them; what this changes is only which text is
561
+ * classified, and the classes are additional evidence about bytes that are
562
+ * bound elsewhere and unchanged.
563
+ */
564
+ export declare function loginShellScript(segment: LexSegment): string | null;
449
565
  /**
450
566
  * The rules whose commands RUN CODE THIS RUNTIME DID NOT AUTHOR (APRV-193).
451
567
  *
@@ -473,6 +589,39 @@ export declare const CODE_EXECUTING_RULES: readonly string[];
473
589
  * it WITH the policy in hand — {@link emittableClass} is that question.
474
590
  */
475
591
  export declare const CLASSIFIER_CLASSES: readonly string[];
592
+ /**
593
+ * The class the DAEMON's own cadence advance is gated as (APRV-382).
594
+ *
595
+ * The sub-class exists because the policy grammar has no actor condition and
596
+ * this repository wanted one: an advance publishes records the log already
597
+ * holds, so the daemon may make it unattended, while the same act from a
598
+ * session in a worktree or a human terminal stays supervised. Two classes are
599
+ * how that is written down, and which of them a cycle asks under is decided by
600
+ * `core/advance-cycle.ts` from the running process, never from an argument.
601
+ *
602
+ * NO COMMAND SPELLS IT, on purpose. `approval log advance` classifies
603
+ * `log.advance` whoever types it, so the looser line is unreachable from a
604
+ * shell an agent can drive: it is reached only from inside the daemon process,
605
+ * which an agent cannot become without a `gate.self` command this policy holds
606
+ * at the manual default.
607
+ */
608
+ export declare const ADVANCE_DAEMON_CLASS = "log.advance.daemon";
609
+ /**
610
+ * Classes this RUNTIME emits for its own gated actions, which no command spells.
611
+ *
612
+ * Separate from {@link CLASSIFIER_CLASSES}, which is the binary table's own set
613
+ * and is what `docs/claude-code-hook.md` documents row by row. A class here is
614
+ * emitted by a runtime cycle that registers and requests it directly — the
615
+ * daemon's advance is the first — so a policy declaring it is declaring a line
616
+ * that CAN fire, and the reachability check `core/policy-expectations.ts` runs
617
+ * at the amendment ceremony must say so. Without this list that ceremony would
618
+ * refuse the line `unreachable`, which is a true statement about the command
619
+ * classifier and a false one about the runtime.
620
+ *
621
+ * Adding a name here is a claim that some path in this codebase asks the gate
622
+ * for that class, and widening it is a reviewable diff.
623
+ */
624
+ export declare const RUNTIME_CLASSES: readonly string[];
476
625
  /**
477
626
  * Can the classifier emit `actionClass` for a project whose policy carries
478
627
  * these `protected_paths`? (APRV-266.)
@@ -488,6 +637,11 @@ export declare const CLASSIFIER_CLASSES: readonly string[];
488
637
  * A routed name is reachable exactly when some entry routes to it. A
489
638
  * `policy.edit.spec` rule in a policy whose `protected_paths` routes nothing to
490
639
  * it is a line that will never fire, and saying so is the whole point.
640
+ *
641
+ * {@link RUNTIME_CLASSES} is the third answer (APRV-382): a class no command
642
+ * spells and a runtime cycle asks for directly is reachable in every project,
643
+ * with no policy entry needed, because the path that emits it is in this
644
+ * codebase rather than in the operator's file.
491
645
  */
492
646
  export declare function emittableClass(actionClass: string, protectedPaths?: readonly ProtectedPathEntry[]): boolean;
493
647
  /**