@mnemom/mnemom 0.17.34-next.1 → 0.17.34-next.3

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 (236) hide show
  1. package/dist/base-url-proxy.mjs +18 -4
  2. package/dist/commands/agent-config.js +5 -1
  3. package/dist/commands/agent-doctor.d.ts +9 -0
  4. package/dist/commands/agent-doctor.js +4 -0
  5. package/dist/commands/agent-run.d.ts +14 -6
  6. package/dist/commands/agent-run.js +44 -27
  7. package/dist/commands/agent-session.d.ts +1 -2
  8. package/dist/commands/agent-session.js +1 -2
  9. package/dist/commands/agent-setup.d.ts +6 -0
  10. package/dist/commands/agent-setup.js +12 -1
  11. package/dist/commands/agent-share-test-issuer.d.ts +67 -0
  12. package/dist/commands/agent-share-test-issuer.js +139 -0
  13. package/dist/commands/agent-share.d.ts +7 -1
  14. package/dist/commands/agent-share.js +14 -4
  15. package/dist/commands/agent.d.ts +18 -5
  16. package/dist/commands/agent.js +186 -59
  17. package/dist/commands/durable-doctor.d.ts +50 -0
  18. package/dist/commands/durable-doctor.js +186 -0
  19. package/dist/commands/durable-lock.d.ts +261 -0
  20. package/dist/commands/durable-lock.js +600 -0
  21. package/dist/commands/durable-sessions.d.ts +87 -0
  22. package/dist/commands/durable-sessions.js +303 -0
  23. package/dist/commands/durable-verbs.d.ts +116 -0
  24. package/dist/commands/durable-verbs.js +393 -0
  25. package/dist/commands/scan.d.ts +12 -1
  26. package/dist/commands/scan.js +22 -3
  27. package/dist/commands/wrap.js +1 -1
  28. package/dist/durable/adopt-live.js +5 -8
  29. package/dist/durable/adopt.d.ts +8 -0
  30. package/dist/durable/adopt.js +27 -6
  31. package/dist/durable/cwd-rule.d.ts +9 -1
  32. package/dist/durable/cwd-rule.js +18 -0
  33. package/dist/durable/flock.d.ts +26 -0
  34. package/dist/durable/flock.js +80 -0
  35. package/dist/durable/launch-spec.d.ts +9 -1
  36. package/dist/durable/launch-spec.js +11 -4
  37. package/dist/durable/seat-proxy-entry.d.ts +11 -0
  38. package/dist/durable/seat-proxy-entry.js +25 -0
  39. package/dist/durable/seat-proxy.d.ts +107 -0
  40. package/dist/durable/seat-proxy.js +599 -0
  41. package/dist/durable/seat-socket.d.ts +46 -0
  42. package/dist/durable/seat-socket.js +179 -0
  43. package/dist/durable/seat-spec-validator.d.ts +28 -0
  44. package/dist/durable/seat-spec-validator.js +59 -0
  45. package/dist/durable/test-mode.mjs +105 -0
  46. package/dist/durable/turn-chain.d.ts +55 -0
  47. package/dist/durable/turn-chain.js +178 -0
  48. package/dist/host/auto-continue.d.ts +67 -0
  49. package/dist/host/auto-continue.js +118 -0
  50. package/dist/host/bootid.d.ts +13 -0
  51. package/dist/host/bootid.js +41 -0
  52. package/dist/host/client.d.ts +125 -0
  53. package/dist/host/client.js +171 -0
  54. package/dist/host/commands.d.ts +2 -0
  55. package/dist/host/commands.js +122 -0
  56. package/dist/host/control.d.ts +33 -0
  57. package/dist/host/control.js +144 -0
  58. package/dist/host/daemon.d.ts +221 -0
  59. package/dist/host/daemon.js +616 -0
  60. package/dist/host/gate.d.ts +46 -0
  61. package/dist/host/gate.js +82 -0
  62. package/dist/host/grant.d.ts +24 -0
  63. package/dist/host/grant.js +24 -0
  64. package/dist/host/instance.d.ts +35 -0
  65. package/dist/host/instance.js +62 -0
  66. package/dist/host/integrity.d.ts +35 -0
  67. package/dist/host/integrity.js +115 -0
  68. package/dist/host/launchd.d.ts +16 -0
  69. package/dist/host/launchd.js +45 -0
  70. package/dist/host/lock.d.ts +20 -0
  71. package/dist/host/lock.js +63 -0
  72. package/dist/host/owner.d.ts +58 -0
  73. package/dist/host/owner.js +123 -0
  74. package/dist/host/plist.d.ts +16 -0
  75. package/dist/host/plist.js +85 -0
  76. package/dist/host/procs.d.ts +27 -0
  77. package/dist/host/procs.js +105 -0
  78. package/dist/host/run.d.ts +65 -0
  79. package/dist/host/run.js +299 -0
  80. package/dist/host/runtime.d.ts +8 -0
  81. package/dist/host/runtime.js +22 -0
  82. package/dist/host/s1-names.d.ts +23 -0
  83. package/dist/host/s1-names.js +22 -0
  84. package/dist/host/seat-credential.d.ts +27 -0
  85. package/dist/host/seat-credential.js +41 -0
  86. package/dist/host/seat-launch-main.d.ts +1 -0
  87. package/dist/host/seat-launch-main.js +59 -0
  88. package/dist/host/seat-launch.d.ts +116 -0
  89. package/dist/host/seat-launch.js +302 -0
  90. package/dist/host/seat.d.ts +48 -0
  91. package/dist/host/seat.js +149 -0
  92. package/dist/host/state.d.ts +33 -0
  93. package/dist/host/state.js +117 -0
  94. package/dist/host/status.d.ts +101 -0
  95. package/dist/host/status.js +307 -0
  96. package/dist/host/tmux.d.ts +56 -0
  97. package/dist/host/tmux.js +182 -0
  98. package/dist/host/transcript.d.ts +30 -0
  99. package/dist/host/transcript.js +130 -0
  100. package/dist/host/verbs.d.ts +52 -0
  101. package/dist/host/verbs.js +282 -0
  102. package/dist/index.d.ts +8 -6
  103. package/dist/index.js +209 -43
  104. package/dist/lib/agent.d.ts +13 -29
  105. package/dist/lib/agent.js +17 -29
  106. package/dist/lib/claude-bin.d.ts +6 -0
  107. package/dist/lib/claude-bin.js +26 -0
  108. package/dist/lib/claude-plugin.d.ts +11 -2
  109. package/dist/lib/claude-plugin.js +10 -1
  110. package/dist/lib/commit-report.d.ts +5 -4
  111. package/dist/lib/commit-report.js +6 -9
  112. package/dist/lib/config.d.ts +8 -1
  113. package/dist/lib/config.js +28 -0
  114. package/dist/lib/durable/api.d.ts +136 -0
  115. package/dist/lib/durable/api.js +220 -0
  116. package/dist/lib/durable/codes.d.ts +8 -0
  117. package/dist/lib/durable/codes.js +2 -0
  118. package/dist/lib/durable/gate.d.ts +48 -0
  119. package/dist/lib/durable/gate.js +122 -0
  120. package/dist/lib/durable/handover.d.ts +101 -0
  121. package/dist/lib/durable/handover.js +175 -0
  122. package/dist/lib/durable/launch.d.ts +199 -0
  123. package/dist/lib/durable/launch.js +461 -0
  124. package/dist/lib/durable/launching.d.ts +15 -0
  125. package/dist/lib/durable/launching.js +70 -0
  126. package/dist/lib/durable/live.d.ts +190 -0
  127. package/dist/lib/durable/live.js +633 -0
  128. package/dist/lib/durable/refusal.d.ts +57 -0
  129. package/dist/lib/durable/refusal.js +78 -0
  130. package/dist/lib/durable/view.d.ts +83 -0
  131. package/dist/lib/durable/view.js +244 -0
  132. package/dist/lib/experimental.d.ts +0 -9
  133. package/dist/lib/experimental.js +18 -17
  134. package/dist/lib/launcher-config.d.ts +13 -0
  135. package/dist/lib/launcher-config.js +32 -0
  136. package/dist/lib/runner/exec-append.d.ts +15 -0
  137. package/dist/lib/runner/exec-append.js +2 -0
  138. package/dist/lib/runner/executor-client.d.ts +2 -1
  139. package/dist/lib/runner/executor-state.d.ts +10 -0
  140. package/dist/lib/runner/executor-state.js +24 -0
  141. package/dist/lib/runner/github-base.d.ts +24 -0
  142. package/dist/lib/runner/github-base.js +27 -0
  143. package/dist/lib/runner/job.d.ts +9 -4
  144. package/dist/lib/runner/job.js +43 -15
  145. package/dist/lib/runner/oidc.d.ts +3 -2
  146. package/dist/lib/runner/oidc.js +7 -4
  147. package/dist/lib/runner/options.d.ts +6 -0
  148. package/dist/lib/runner/options.js +19 -1
  149. package/dist/lib/runner/phases.d.ts +7 -4
  150. package/dist/lib/runner/phases.js +8 -4
  151. package/dist/lib/runner/proxy.d.ts +5 -1
  152. package/dist/lib/runner/proxy.js +7 -1
  153. package/dist/lib/scan/cost-per-pr.d.ts +93 -0
  154. package/dist/lib/scan/cost-per-pr.js +101 -0
  155. package/dist/lib/scan/record.d.ts +27 -1
  156. package/dist/lib/scan/record.js +114 -16
  157. package/dist/lib/scan/report-email.d.ts +26 -6
  158. package/dist/lib/scan/report-email.js +32 -3
  159. package/dist/lib/scan/scan.d.ts +3 -0
  160. package/dist/lib/scan/scan.js +13 -1
  161. package/dist/lib/subscription-login.d.ts +15 -0
  162. package/dist/lib/subscription-login.js +28 -1
  163. package/dist/vendor/durable-contract/index.js +240 -18
  164. package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
  165. package/dist/vendor/shared/durable-contract/admission.js +533 -0
  166. package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
  167. package/dist/vendor/shared/durable-contract/arm.js +133 -0
  168. package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
  169. package/dist/vendor/shared/durable-contract/canonical.js +98 -0
  170. package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
  171. package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
  172. package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
  173. package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
  174. package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
  175. package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
  176. package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
  177. package/dist/vendor/shared/durable-contract/codes.js +475 -0
  178. package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
  179. package/dist/vendor/shared/durable-contract/constants.js +179 -0
  180. package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
  181. package/dist/vendor/shared/durable-contract/doors.js +249 -0
  182. package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
  183. package/dist/vendor/shared/durable-contract/envelope.js +317 -0
  184. package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
  185. package/dist/vendor/shared/durable-contract/events.js +630 -0
  186. package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
  187. package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
  188. package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
  189. package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
  190. package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
  191. package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
  192. package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
  193. package/dist/vendor/shared/durable-contract/index.js +37 -0
  194. package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
  195. package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
  196. package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
  197. package/dist/vendor/shared/durable-contract/keys.js +66 -0
  198. package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
  199. package/dist/vendor/shared/durable-contract/lock.js +151 -0
  200. package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
  201. package/dist/vendor/shared/durable-contract/names.js +78 -0
  202. package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
  203. package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
  204. package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
  205. package/dist/vendor/shared/durable-contract/paths.js +35 -0
  206. package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
  207. package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
  208. package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
  209. package/dist/vendor/shared/durable-contract/routes.js +315 -0
  210. package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
  211. package/dist/vendor/shared/durable-contract/schema.js +441 -0
  212. package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
  213. package/dist/vendor/shared/durable-contract/seal.js +99 -0
  214. package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
  215. package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
  216. package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
  217. package/dist/vendor/shared/durable-contract/session-id.js +58 -0
  218. package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
  219. package/dist/vendor/shared/durable-contract/spec.js +286 -0
  220. package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
  221. package/dist/vendor/shared/durable-contract/states.js +218 -0
  222. package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
  223. package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
  224. package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
  225. package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
  226. package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
  227. package/dist/vendor/shared/durable-contract/turn.js +81 -0
  228. package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
  229. package/dist/vendor/shared/durable-contract/vectors.js +208 -0
  230. package/package.json +3 -2
  231. package/plugins/integrity-manifest.json +35 -0
  232. package/plugins/mnemom/hooks/hooks.json +15 -1
  233. package/plugins/mnemom/hooks/register.tsx +60 -2
  234. package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
  235. package/dist/commands/agent-implicit-notice.d.ts +0 -31
  236. package/dist/commands/agent-implicit-notice.js +0 -73
@@ -0,0 +1,179 @@
1
+ // GENERATED from shared/durable-contract/src/constants.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * Every frozen durable constant (BACKBONE "Pieces / S1", amendments 33-50). A spec or piece cites
4
+ * these by name and never restates a different value. The values the backbone left to "the S1
5
+ * freeze record" are chosen here; each carries its reason. `freeze-record.ts` copies them into
6
+ * the JSON record the eval runner reads as `$S1.<NAME>`.
7
+ */
8
+ /** The contract version of this package. Any change to FREEZE.json bumps it. */
9
+ export const DURABLE_CONTRACT_VERSION = "1.0.0";
10
+ /**
11
+ * `durable_schema_version()` must return exactly this. A mismatch makes the entitlement `durable`
12
+ * field absent and a claim answers 503 durable_claim_unavailable {cause:"schema"} (A3).
13
+ */
14
+ export const DURABLE_SCHEMA_VERSION = 1;
15
+ // ---- Lease clock (DB settings with these prod defaults; not TEST_MODE seams) ----------------
16
+ /** durable_cell_state.lease_seconds default, CHECK LEASE_SECONDS_MIN..LEASE_SECONDS_MAX. */
17
+ export const LEASE_SECONDS_DEFAULT = 90;
18
+ export const LEASE_SECONDS_MIN = 5;
19
+ export const LEASE_SECONDS_MAX = 90;
20
+ /** durable_cell_state.resume_reset_seconds default, CHECK RESUME_RESET_SECONDS_MIN..MAX. */
21
+ export const RESUME_RESET_SECONDS_DEFAULT = 600;
22
+ export const RESUME_RESET_SECONDS_MIN = 5;
23
+ export const RESUME_RESET_SECONDS_MAX = 600;
24
+ /** Heartbeat period = lease_seconds / HEARTBEAT_DIVISOR (30 s at 90, 2 s at 6). */
25
+ export const HEARTBEAT_DIVISOR = 3;
26
+ /** resume_failures at which a session goes to suspended(respawn_failed). */
27
+ export const RESPAWN_FAILURES_SUSPEND_AT = 3;
28
+ /** Seats the daemon respawns at once. */
29
+ export const RESPAWN_CONCURRENCY = 4;
30
+ // ---- Gateway --------------------------------------------------------------------------------
31
+ /** resolve_durable_session_key touches last_used_at only when NULL or older than this (DB clock). */
32
+ export const LEASE_KEY_TOUCH_SECONDS = 60;
33
+ /** M1 has no stale serve: every resolver fault is 503 durable_admission_unavailable (I20). */
34
+ export const STALE_SERVE_M1 = false;
35
+ /** M1 honours DURABLE_ADMIT, but only for the exact bytes NOFENCE_ADMIT_VALUE (r3 I01). */
36
+ export const NOFENCE_M1 = true;
37
+ export const NOFENCE_ADMIT_VALUE = "nofence";
38
+ /** Upper bound for one resolver RPC; past it the gateway answers 503 (C06-R07 "timeout T"). */
39
+ export const RESOLVER_TIMEOUT_MS = 2000;
40
+ // ---- API executor plane ---------------------------------------------------------------------
41
+ /** Claim-time arm probe (GET /internal/durable/arm at the home cell) must answer within this. */
42
+ export const ARM_PROBE_TIMEOUT_MS = 2000;
43
+ /** A parseable arm probe answer is cached at most this long. */
44
+ export const ARM_PROBE_TTL_S = 10;
45
+ /** Check 12: a `protected` answer is cached per (repo, branch) this long. */
46
+ export const PROTECTION_CACHE_S = 300;
47
+ /** Executor grant: renewal sets grant_expires_at = now() + GRANT_TTL_S. */
48
+ export const GRANT_TTL_S = 30 * 24 * 3600;
49
+ /** sessions, show and host status warn in the last GRANT_WARNING_S of the grant. */
50
+ export const GRANT_WARNING_S = 7.5 * 24 * 3600;
51
+ /** Clean seat exits (exit 0 after an accepted hello) beyond CLEAN_EXIT_MAX in the window count as failures. */
52
+ export const CLEAN_EXIT_MAX = 3;
53
+ export const CLEAN_EXIT_WINDOW_S = 600;
54
+ // ---- Host daemon ----------------------------------------------------------------------------
55
+ /** The daemon polls GET /v1/executor/sessions every EXECUTOR_POLL_S. */
56
+ export const EXECUTOR_POLL_S = 10;
57
+ /** An executor whose last_seen_at is older than this is not live. */
58
+ export const EXECUTOR_LIVE_S = 3 * EXECUTOR_POLL_S;
59
+ /** Claim backoff on 503 durable_claim_unavailable: CLAIM_BACKOFF_BASE_S doubling to CLAIM_BACKOFF_MAX_S. */
60
+ export const CLAIM_BACKOFF_BASE_S = 2;
61
+ export const CLAIM_BACKOFF_MAX_S = 60;
62
+ /** Each backoff delay is stretched by a factor in [1, 1 + CLAIM_BACKOFF_JITTER). */
63
+ export const CLAIM_BACKOFF_JITTER = 0.2;
64
+ /** host status prints the guard fix after more than this many consecutive `guard` unavailable claims. */
65
+ export const CLAIM_UNAVAILABLE_SURFACE_N = 5;
66
+ /** SIGTERM to SIGKILL grace when done/kill stops a local tracked claude (final F04). */
67
+ export const TRACKED_STOP_GRACE_S = 5;
68
+ // ---- Seat / credential proxy ----------------------------------------------------------------
69
+ /**
70
+ * Upstream attempts one typed turn may produce on a non-retryable refusal (C13-R14). Expected 1;
71
+ * PROVISIONAL until the day-1 spike with claude 2.1.285 records the real number.
72
+ */
73
+ export const SEAT_MAX_ATTEMPTS_NONRETRY = 1;
74
+ /** A synced main request waits up to TURN_WAIT_MS for its prompt (= cli/src/turn-origin.mjs WAIT_MS on origin/main). */
75
+ export const TURN_WAIT_MS = 500;
76
+ /** x-mnemom-turn limits, equal to gateway/src/goal-turn-claims.ts. */
77
+ export const TURN_HEADER_MAX_LEN = 8192;
78
+ export const TURN_ENTRIES_MAX = 32;
79
+ // ---- Sweep (C20-R12) ------------------------------------------------------------------------
80
+ /** One global row cap across all categories per run. */
81
+ export const SWEEP_MAX_ROWS = 200;
82
+ /** Rows per batch; SWEEP_BATCH_SIZE < SWEEP_MAX_ROWS. */
83
+ export const SWEEP_BATCH_SIZE = 50;
84
+ /** Time budget T per run. */
85
+ export const SWEEP_TIME_BUDGET_MS = 10000;
86
+ export const SWEEP_CRON = "*/5 * * * *";
87
+ // ---- Budget, contract, journal --------------------------------------------------------------
88
+ /**
89
+ * The per-session budget limit in USD, code-fixed and conservative (owner Q2). The single source
90
+ * for the amend bound, the 422 and the gateway 429; durable_org_policy.limits is seeded from it
91
+ * and not read in M1 (parity test: seed == constant).
92
+ */
93
+ export const PER_SESSION_BUDGET_LIMIT_USD = 20;
94
+ /** durable_org_policy.limits seed, built from the constant above. */
95
+ export const ORG_POLICY_LIMITS_SEED = Object.freeze({
96
+ per_session_budget_usd: PER_SESSION_BUDGET_LIMIT_USD,
97
+ });
98
+ /** The API's frozen contract statement limit (= gateway goal-contract STATEMENT_MAX). */
99
+ export const CONTRACT_STATEMENT_MAX_CHARS = 4000;
100
+ /** canonicalJson of the whole contract plaintext (= gateway goal-contract CONTRACT_JSON_MAX). */
101
+ export const CONTRACT_JSON_MAX_BYTES = 8192;
102
+ /** agent_session_events.detail is server-generated and at most this many characters. */
103
+ export const EVENT_DETAIL_MAX_CHARS = 280;
104
+ /** contract_ciphertext is purged this long after the session ends. */
105
+ export const CONTRACT_PURGE_AFTER_S = 30 * 24 * 3600;
106
+ // ---- Device step (A4) -----------------------------------------------------------------------
107
+ /** owner_mutation needs aal2 and a step-up no older than this. */
108
+ export const DEVICE_STEP_FRESHNESS_S = 300;
109
+ /**
110
+ * The cookie SessionBlob key holding the step-up time, integer unix seconds, optional (ruling 27;
111
+ * C16-R10). Fresh when 0 <= now - su <= DEVICE_STEP_FRESHNESS_S; an absent or future su is stale.
112
+ * Separate from `ia`: a step-up renews freshness without extending the session's lifetime.
113
+ */
114
+ export const STEP_UP_BLOB_FIELD = "su";
115
+ /** An owner_mutation approval expires with its device code (= api DEVICE_CODE_TTL_SECONDS). */
116
+ export const OWNER_MUTATION_APPROVAL_TTL_S = 15 * 60;
117
+ /** The CLI polls the device grant this often (= api DEVICE_POLL_INTERVAL_SECONDS). */
118
+ export const DEVICE_POLL_INTERVAL_S = 5;
119
+ // ---- Versions -------------------------------------------------------------------------------
120
+ /** The laptop risk-line text version (fixlines.ts RISK_LINE_TEXT). Bump with any text change. */
121
+ export const RISK_LINE_VERSION = 1;
122
+ /** RISK_LINE_VERSION as the decimal text the A1 column, the page marker and the enrollment approval subject carry (ruling 32.30). */
123
+ export const RISK_LINE_VERSION_TEXT = String(RISK_LINE_VERSION);
124
+ /** The --settings / --mcp-config renderer version recorded in attestation.passed (spec.ts). */
125
+ export const RENDERER_VERSION = 1;
126
+ /** The plugin dir-hash recipe version (spec.ts pluginDirHash). */
127
+ export const PLUGIN_HASH_RECIPE_VERSION = 1;
128
+ /** The journal preimage version (events.ts EVENT_PREIMAGE_FIELDS). */
129
+ export const EVENT_PREIMAGE_VERSION = 1;
130
+ /**
131
+ * L_spawn, the lease every real-claude case runs at (20..90), set by ruling 34.17 (calibration):
132
+ * max(20, ceil(3 x p100 claim-to-hello)) s, capped at 90, with p100 the maximum over the clean
133
+ * calibration runs (2.616 s, run42), so max(20, 8) = 20. Re-derived only by a new calibration ruling.
134
+ */
135
+ export const L_SPAWN = 20;
136
+ export const L_SPAWN_MIN = 20;
137
+ export const L_SPAWN_MAX = 90;
138
+ /**
139
+ * T_hello, the calibrated per-seat spawn-to-hello time in seconds (C12-R31 recovery bound), set by
140
+ * the same ruling 34.17 calibration as L_SPAWN: p100 claim-to-hello at 4
141
+ * concurrent respawns, the maximum over the clean runs (run41 1.873, run42 2.616).
142
+ */
143
+ export const T_HELLO_S = 2.616;
144
+ /**
145
+ * The first-party public OAuth client an owner_mutation device code is bound to (C16-R01; wave-0
146
+ * fix ruling 1.12). A1 seeds it; every 202 device-step body returns it as client_id; the generic
147
+ * /v1/oauth/device_authorization refuses it for every scope (C16-A-032). The CLI's login client is
148
+ * NOT frozen: it is issued by RFC 7591 dynamic registration.
149
+ */
150
+ export const OWNER_MUTATION_CLIENT_ID = "mnemom-durable-owner-mutation";
151
+ /** ATTACH_WAIT_S = EXECUTOR_POLL_S + lease_seconds (BACKBONE). Throws outside the lease CHECK range. */
152
+ export function attachWaitSeconds(leaseSeconds) {
153
+ if (!Number.isInteger(leaseSeconds) ||
154
+ leaseSeconds < LEASE_SECONDS_MIN ||
155
+ leaseSeconds > LEASE_SECONDS_MAX) {
156
+ throw new RangeError(`lease_seconds out of range: ${leaseSeconds}`);
157
+ }
158
+ return EXECUTOR_POLL_S + leaseSeconds;
159
+ }
160
+ /** ATTACH_WAIT_S at the default 90 s lease. */
161
+ export const ATTACH_WAIT_S = EXECUTOR_POLL_S + LEASE_SECONDS_DEFAULT;
162
+ /** Heartbeat period in seconds for a lease, derived from the server's lease. */
163
+ export function heartbeatSeconds(leaseSeconds) {
164
+ return leaseSeconds / HEARTBEAT_DIVISOR;
165
+ }
166
+ /**
167
+ * Delay before claim attempt `attempt` (1-based) after consecutive 503 durable_claim_unavailable
168
+ * answers: CLAIM_BACKOFF_BASE_S * 2^(attempt-1), capped at CLAIM_BACKOFF_MAX_S, stretched by
169
+ * (1 + CLAIM_BACKOFF_JITTER * r) where r in [0, 1) is the caller's random draw. So no gap is under
170
+ * 2 s and none is over 60 s x (1 + CLAIM_BACKOFF_JITTER) (C12-R30).
171
+ */
172
+ export function claimBackoffMs(attempt, r) {
173
+ if (!Number.isInteger(attempt) || attempt < 1)
174
+ throw new RangeError(`attempt must be >= 1: ${attempt}`);
175
+ if (!(r >= 0 && r < 1))
176
+ throw new RangeError(`r must be in [0, 1): ${r}`);
177
+ const base = Math.min(CLAIM_BACKOFF_BASE_S * 2 ** (attempt - 1), CLAIM_BACKOFF_MAX_S);
178
+ return Math.round(base * 1000 * (1 + CLAIM_BACKOFF_JITTER * r));
179
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The Doors amendment to M1's claim model (rulings 34.01, 34.03, 34.05, 34.05.1, 34.10, 34.12):
3
+ * the pool-claim flag, executor scope, the per-org live-lease cap, the dispatch constructor's
4
+ * names and answers, and the thin runner's (`mnemom agent run`) frozen outcome line.
5
+ */
6
+ /** The api env flag that gates every pool behaviour; its value is the org allowlist. */
7
+ export declare const DURABLE_POOL_CLAIM_FLAG = "DURABLE_POOL_CLAIM";
8
+ /**
9
+ * Whether the pool claim is on for `orgId`. The flag's value is a comma-separated list of org ids
10
+ * (whitespace around each ignored). Unset, empty, or any malformed entry reads as off for every
11
+ * org: an unknown value is never a partial allowlist (Doors production safety 1).
12
+ */
13
+ export declare function poolClaimEnabled(flagValue: string | undefined, orgId: string): boolean;
14
+ /** The session facts isPoolSession reads. */
15
+ export interface PoolSessionFacts {
16
+ readonly home_executor_id: string | null;
17
+ readonly durable_mode: string;
18
+ readonly org_id: string;
19
+ }
20
+ /**
21
+ * Whether a session is a pool session (rulings 34.04.1, 34.14 (3)): home_executor_id NULL, locked,
22
+ * and its org in the flag's allowlist. This is EffectiveStateInput.pool; the api and A1's parity
23
+ * test import it and never copy it. A NULL home alone (an erased executor) is never enough.
24
+ */
25
+ export declare function isPoolSession(s: PoolSessionFacts, flagValue: string | undefined): boolean;
26
+ /**
27
+ * The flag's org allowlist, in order with duplicates dropped; [] when the flag is off (unset, empty,
28
+ * or any malformed entry). The api imports this, never a copy: 34.10 (g)(3)'s p_org_ids is its
29
+ * answer.
30
+ */
31
+ export declare function poolClaimOrgs(flagValue: string | undefined): string[];
32
+ export declare const EXECUTOR_SCOPES: readonly ["user", "org"];
33
+ export type ExecutorScope = (typeof EXECUTOR_SCOPES)[number];
34
+ /** Only these executor kinds may enroll with scope org. */
35
+ export declare const ORG_SCOPE_EXECUTOR_KINDS: readonly ["container", "fleet"];
36
+ /** exec_oidc_exchange refusals (ruling 34.03's S1 changes). */
37
+ export declare const OIDC_EXCHANGE_REFUSALS: readonly ["bad_issuer", "repo_not_enrolled", "ref_not_allowed", "pool_flag_off"];
38
+ /** The audience a GitHub OIDC token must name for exec_oidc_exchange (ruling 34.12 (5)). */
39
+ export declare const OIDC_EXCHANGE_AUDIENCE = "mnemom-executor";
40
+ /** durable_org_policy.limits keys (34.05 (1)); live_lease_cap is optional. */
41
+ export declare const ORG_POLICY_LIMIT_KEYS: readonly ["per_session_budget_usd", "live_lease_cap"];
42
+ /** live_lease_cap and the registry default share this range. */
43
+ export declare const LIVE_LEASE_CAP_MIN = 1;
44
+ export declare const LIVE_LEASE_CAP_MAX = 1000;
45
+ /** The org advisory lock a pool claim takes: pg_advisory_xact_lock(hashtext(prefix || org_id)). */
46
+ export declare const ORG_CAP_LOCK_PREFIX = "durable_org_cap:";
47
+ /** The api env var carrying the registry's dispatch.per_org_lease_cap (34.05.1 (2)). */
48
+ export declare const DEFAULT_LEASE_CAP_ENV = "DURABLE_DEFAULT_LEASE_CAP";
49
+ /** DURABLE_DEFAULT_LEASE_CAP as an integer, or null when absent or invalid (34.05.1 (3): fail closed). */
50
+ export declare function parseDefaultLeaseCap(envValue: string | undefined): number | null;
51
+ /**
52
+ * The effective cap of a pool claim (34.05.1 (1)): the org row's limits.live_lease_cap, else the
53
+ * default row's, else the registry default. Absent or NULL falls through; any present value out of
54
+ * range (even one that would not win), or no value at all, throws (the claim answers 503 lease_cap_config, never "no cap").
55
+ */
56
+ export declare function effectiveLeaseCap(orgLimits: {
57
+ readonly live_lease_cap?: number | null;
58
+ } | null, defaultRowLimits: {
59
+ readonly live_lease_cap?: number | null;
60
+ } | null, defaultCap: number | null): number;
61
+ export declare const DISPATCH_SESSION_CID_PREFIX = "dispatch-";
62
+ export declare const DISPATCH_SESSION_NAME_PREFIX = "job-";
63
+ export declare const CREATE_READY_SESSION_REFUSALS: readonly ["no_dispatch_agent", "seal_not_found", "cell_unmapped", "charter_mismatch"];
64
+ export declare const CREATE_READY_SESSION_OUTCOMES: readonly ["created", "existing", "refused"];
65
+ /** durable_create_ready_session's answer keys per outcome, closed (34.10 (g)(1)). */
66
+ export declare const CREATE_READY_SESSION_ANSWERS: Readonly<{
67
+ readonly created: readonly ["outcome", "session_id"];
68
+ readonly existing: readonly ["outcome", "session_id"];
69
+ readonly refused: readonly ["outcome", "reason"];
70
+ }>;
71
+ /** Whether `v` is a closed answer: its outcome's keys only, a lowercase uuid session_id or a listed reason. */
72
+ export declare function createReadySessionAnswerOk(v: unknown): boolean;
73
+ /** conversation_id = 'dispatch-' || seal_id: 45 characters, so it passes ID_RE (34.10 (b)). */
74
+ export declare function dispatchConversationId(sealId: string): string;
75
+ /** name = 'job-' || the first 12 hex characters of seal_id without dashes, 16 characters (34.10 (c)). */
76
+ export declare function dispatchSessionName(sealId: string): string;
77
+ export declare const RUNNER_OUTCOMES: readonly ["done", "no_job", "failed", "refused"];
78
+ export type RunnerOutcome = (typeof RUNNER_OUTCOMES)[number];
79
+ /** The v1 outcome line's fields, in order, each always present (34.12 (8)). */
80
+ export declare const RUNNER_OUTCOME_FIELDS: readonly ["v", "outcome", "session_id", "lease_epoch", "contract_sha256", "contract_version", "merge_strategy", "pr_url", "reason"];
81
+ /** Exit code per outcome (34.12 (6)); usage errors and the gate exit 2. */
82
+ export declare const RUNNER_EXIT_CODES: Readonly<{
83
+ readonly done: 0;
84
+ readonly no_job: 0;
85
+ readonly failed: 1;
86
+ readonly usage: 2;
87
+ readonly refused: 3;
88
+ }>;
89
+ /** failed reasons besides the phase pattern RUNNER_FAILED_PHASE_RE. */
90
+ export declare const RUNNER_FAILED_REASONS: readonly ["pr_open_failed"];
91
+ export declare const RUNNER_FAILED_PHASE_RE: RegExp;
92
+ /** The closed refused list (34.12 (8)). */
93
+ export declare const RUNNER_REFUSED_REASONS: readonly ["bundle_too_large", "bundle_malformed", "bundle_wrong_typ", "bundle_schema", "bundle_unknown_key", "bundle_unusable_key", "bundle_retired_key", "bundle_bad_signature", "bundle_code_digest_mismatch", "bundle_not_yet_valid", "bundle_expired", "bundle_binding_mismatch", "bundle_unavailable", "job_unavailable", "contract_bad_sha", "contract_too_large", "contract_sha_mismatch", "contract_not_a_contract", "contract_mismatch_unrecoverable", "claim_needs_key", "claim_ineligible", "claim_unavailable", "lease_lost", "executor_revoked", "executor_unauthorized", "oidc_bad_issuer", "oidc_repo_not_enrolled", "oidc_ref_not_allowed", "oidc_pool_flag_off", "oidc_unavailable", "api_unavailable"];
94
+ /** Under --fail-mode open, only these may be ridden through, and only once a verified bundle is held (34.12 (2)). */
95
+ export declare const RUNNER_OPEN_MODE_TOLERATED: readonly ["bundle_unavailable", "job_unavailable", "api_unavailable"];
96
+ export declare const RUNNER_MERGE_STRATEGIES: readonly ["external", "merge_on_green"];
97
+ /**
98
+ * The fields a 200 claim answer carries exactly when the session is a pool session: the charter's
99
+ * contract_sha256 and contract_version, and the effective cap. A homed claim's answer carries none.
100
+ */
101
+ export declare const POOL_CLAIM_FIELDS: readonly ["contract_sha256", "contract_version", "cap"];
102
+ /** Whether a 200 claim answer's pool fields match `pool` (other keys are not judged here). */
103
+ export declare function poolClaimFieldsOk(body: Readonly<Record<string, unknown>>, pool: boolean): boolean;
104
+ /**
105
+ * agent_sessions.wait_ref, closed per PARKED_ONLY_WAIT_REASONS value (34.06 (2)): commitments only.
106
+ * repo_id is GitHub's numeric repository.id, a positive integer (ruling 34.14 (6)).
107
+ */
108
+ export declare const WAIT_REF_KEYS: Readonly<{
109
+ readonly ci: readonly ["repo_id", "head_sha"];
110
+ readonly question: readonly ["approval_id"];
111
+ readonly budget: readonly ["approval_id"];
112
+ }>;
113
+ /** Whether `ref` is exactly the wait_ref shape for `reason`. */
114
+ export declare function waitRefOk(reason: string, ref: unknown): boolean;
115
+ /** durable_clear_wait answers (34.06 (4)). */
116
+ export declare const CLEAR_WAIT_OUTCOMES: readonly ["cleared", "stale_ref", "already_clear"];
117
+ /** durable_ready_sessions p_limit and exec_ready_list ?limit= range (34.03 (3)). */
118
+ export declare const READY_SESSIONS_LIMIT_MIN = 1;
119
+ export declare const READY_SESSIONS_LIMIT_MAX = 50;
@@ -0,0 +1,249 @@
1
+ // GENERATED from shared/durable-contract/src/doors.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * The Doors amendment to M1's claim model (rulings 34.01, 34.03, 34.05, 34.05.1, 34.10, 34.12):
4
+ * the pool-claim flag, executor scope, the per-org live-lease cap, the dispatch constructor's
5
+ * names and answers, and the thin runner's (`mnemom agent run`) frozen outcome line.
6
+ */
7
+ import { ID_RE } from "./paths.js";
8
+ import { UUID_RE } from "./canonical.js";
9
+ // ---- Flag (ruling 34.01 (1), (2)) -----------------------------------------------------------
10
+ /** The api env flag that gates every pool behaviour; its value is the org allowlist. */
11
+ export const DURABLE_POOL_CLAIM_FLAG = "DURABLE_POOL_CLAIM";
12
+ /**
13
+ * Whether the pool claim is on for `orgId`. The flag's value is a comma-separated list of org ids
14
+ * (whitespace around each ignored). Unset, empty, or any malformed entry reads as off for every
15
+ * org: an unknown value is never a partial allowlist (Doors production safety 1).
16
+ */
17
+ export function poolClaimEnabled(flagValue, orgId) {
18
+ return poolClaimOrgs(flagValue).includes(orgId);
19
+ }
20
+ /**
21
+ * Whether a session is a pool session (rulings 34.04.1, 34.14 (3)): home_executor_id NULL, locked,
22
+ * and its org in the flag's allowlist. This is EffectiveStateInput.pool; the api and A1's parity
23
+ * test import it and never copy it. A NULL home alone (an erased executor) is never enough.
24
+ */
25
+ export function isPoolSession(s, flagValue) {
26
+ return (s.home_executor_id === null &&
27
+ s.durable_mode === "locked" &&
28
+ poolClaimEnabled(flagValue, s.org_id));
29
+ }
30
+ /**
31
+ * The flag's org allowlist, in order with duplicates dropped; [] when the flag is off (unset, empty,
32
+ * or any malformed entry). The api imports this, never a copy: 34.10 (g)(3)'s p_org_ids is its
33
+ * answer.
34
+ */
35
+ export function poolClaimOrgs(flagValue) {
36
+ if (flagValue === undefined)
37
+ return [];
38
+ const orgs = flagValue.split(",").map((s) => s.trim());
39
+ if (orgs.some((o) => !ID_RE.test(o)))
40
+ return [];
41
+ return [...new Set(orgs)];
42
+ }
43
+ // ---- Executor scope (ruling 34.03 (1)) ------------------------------------------------------
44
+ export const EXECUTOR_SCOPES = ["user", "org"];
45
+ /** Only these executor kinds may enroll with scope org. */
46
+ export const ORG_SCOPE_EXECUTOR_KINDS = ["container", "fleet"];
47
+ /** exec_oidc_exchange refusals (ruling 34.03's S1 changes). */
48
+ export const OIDC_EXCHANGE_REFUSALS = [
49
+ "bad_issuer",
50
+ "repo_not_enrolled",
51
+ "ref_not_allowed",
52
+ "pool_flag_off",
53
+ ];
54
+ /** The audience a GitHub OIDC token must name for exec_oidc_exchange (ruling 34.12 (5)). */
55
+ export const OIDC_EXCHANGE_AUDIENCE = "mnemom-executor";
56
+ // ---- Per-org live-lease cap (rulings 34.05, 34.05.1) ----------------------------------------
57
+ /** durable_org_policy.limits keys (34.05 (1)); live_lease_cap is optional. */
58
+ export const ORG_POLICY_LIMIT_KEYS = ["per_session_budget_usd", "live_lease_cap"];
59
+ /** live_lease_cap and the registry default share this range. */
60
+ export const LIVE_LEASE_CAP_MIN = 1;
61
+ export const LIVE_LEASE_CAP_MAX = 1000;
62
+ /** The org advisory lock a pool claim takes: pg_advisory_xact_lock(hashtext(prefix || org_id)). */
63
+ export const ORG_CAP_LOCK_PREFIX = "durable_org_cap:";
64
+ /** The api env var carrying the registry's dispatch.per_org_lease_cap (34.05.1 (2)). */
65
+ export const DEFAULT_LEASE_CAP_ENV = "DURABLE_DEFAULT_LEASE_CAP";
66
+ const capOk = (v) => Number.isInteger(v) && v >= LIVE_LEASE_CAP_MIN && v <= LIVE_LEASE_CAP_MAX;
67
+ /** DURABLE_DEFAULT_LEASE_CAP as an integer, or null when absent or invalid (34.05.1 (3): fail closed). */
68
+ export function parseDefaultLeaseCap(envValue) {
69
+ if (envValue === undefined || !/^[1-9][0-9]{0,3}$/.test(envValue))
70
+ return null;
71
+ const n = Number(envValue);
72
+ return capOk(n) ? n : null;
73
+ }
74
+ /**
75
+ * The effective cap of a pool claim (34.05.1 (1)): the org row's limits.live_lease_cap, else the
76
+ * default row's, else the registry default. Absent or NULL falls through; any present value out of
77
+ * range (even one that would not win), or no value at all, throws (the claim answers 503 lease_cap_config, never "no cap").
78
+ */
79
+ export function effectiveLeaseCap(orgLimits, defaultRowLimits, defaultCap) {
80
+ const present = [orgLimits?.live_lease_cap, defaultRowLimits?.live_lease_cap, defaultCap].filter((v) => v !== undefined && v !== null);
81
+ // every present value is range-checked, not only the one that wins
82
+ for (const v of present)
83
+ if (!capOk(v))
84
+ throw new RangeError(`live lease cap out of range: ${String(v)}`);
85
+ if (present.length === 0)
86
+ throw new RangeError("no live lease cap: DURABLE_DEFAULT_LEASE_CAP is unset");
87
+ return present[0];
88
+ }
89
+ // ---- Dispatch constructor (ruling 34.10) ----------------------------------------------------
90
+ export const DISPATCH_SESSION_CID_PREFIX = "dispatch-";
91
+ export const DISPATCH_SESSION_NAME_PREFIX = "job-";
92
+ export const CREATE_READY_SESSION_REFUSALS = [
93
+ "no_dispatch_agent",
94
+ "seal_not_found",
95
+ "cell_unmapped",
96
+ // 34.10.1 (4): the api-built charter v1 or its envelope does not match the seal; nothing written
97
+ "charter_mismatch",
98
+ ];
99
+ export const CREATE_READY_SESSION_OUTCOMES = ["created", "existing", "refused"];
100
+ /** durable_create_ready_session's answer keys per outcome, closed (34.10 (g)(1)). */
101
+ export const CREATE_READY_SESSION_ANSWERS = Object.freeze({
102
+ created: ["outcome", "session_id"],
103
+ existing: ["outcome", "session_id"],
104
+ refused: ["outcome", "reason"],
105
+ });
106
+ /** Whether `v` is a closed answer: its outcome's keys only, a lowercase uuid session_id or a listed reason. */
107
+ export function createReadySessionAnswerOk(v) {
108
+ if (v === null || typeof v !== "object" || Array.isArray(v))
109
+ return false;
110
+ const a = v;
111
+ if (typeof a.outcome !== "string" ||
112
+ !Object.prototype.hasOwnProperty.call(CREATE_READY_SESSION_ANSWERS, a.outcome))
113
+ return false;
114
+ const keys = CREATE_READY_SESSION_ANSWERS[a.outcome];
115
+ if (Object.keys(a).length !== keys.length || !keys.every((k) => k in a))
116
+ return false;
117
+ return a.outcome === "refused"
118
+ ? CREATE_READY_SESSION_REFUSALS.includes(a.reason)
119
+ : typeof a.session_id === "string" && UUID_RE.test(a.session_id);
120
+ }
121
+ function sealIdOk(sealId) {
122
+ if (!UUID_RE.test(sealId))
123
+ throw new RangeError(`seal id must be a lowercase uuid: ${sealId}`);
124
+ return sealId;
125
+ }
126
+ /** conversation_id = 'dispatch-' || seal_id: 45 characters, so it passes ID_RE (34.10 (b)). */
127
+ export function dispatchConversationId(sealId) {
128
+ return DISPATCH_SESSION_CID_PREFIX + sealIdOk(sealId);
129
+ }
130
+ /** name = 'job-' || the first 12 hex characters of seal_id without dashes, 16 characters (34.10 (c)). */
131
+ export function dispatchSessionName(sealId) {
132
+ return DISPATCH_SESSION_NAME_PREFIX + sealIdOk(sealId).replace(/-/g, "").slice(0, 12);
133
+ }
134
+ // ---- Thin runner (ruling 34.12) -------------------------------------------------------------
135
+ export const RUNNER_OUTCOMES = ["done", "no_job", "failed", "refused"];
136
+ /** The v1 outcome line's fields, in order, each always present (34.12 (8)). */
137
+ export const RUNNER_OUTCOME_FIELDS = [
138
+ "v",
139
+ "outcome",
140
+ "session_id",
141
+ "lease_epoch",
142
+ "contract_sha256",
143
+ "contract_version",
144
+ "merge_strategy",
145
+ "pr_url",
146
+ "reason",
147
+ ];
148
+ /** Exit code per outcome (34.12 (6)); usage errors and the gate exit 2. */
149
+ export const RUNNER_EXIT_CODES = Object.freeze({
150
+ done: 0,
151
+ no_job: 0,
152
+ failed: 1,
153
+ usage: 2,
154
+ refused: 3,
155
+ });
156
+ /** failed reasons besides the phase pattern RUNNER_FAILED_PHASE_RE. */
157
+ export const RUNNER_FAILED_REASONS = ["pr_open_failed"];
158
+ export const RUNNER_FAILED_PHASE_RE = /^phase_[0-9]+_[a-z0-9_]+$/;
159
+ /** The closed refused list (34.12 (8)). */
160
+ export const RUNNER_REFUSED_REASONS = [
161
+ "bundle_too_large",
162
+ "bundle_malformed",
163
+ "bundle_wrong_typ",
164
+ "bundle_schema",
165
+ "bundle_unknown_key",
166
+ "bundle_unusable_key",
167
+ "bundle_retired_key",
168
+ "bundle_bad_signature",
169
+ "bundle_code_digest_mismatch",
170
+ "bundle_not_yet_valid",
171
+ "bundle_expired",
172
+ "bundle_binding_mismatch",
173
+ "bundle_unavailable",
174
+ "job_unavailable",
175
+ "contract_bad_sha",
176
+ "contract_too_large",
177
+ "contract_sha_mismatch",
178
+ "contract_not_a_contract",
179
+ "contract_mismatch_unrecoverable",
180
+ "claim_needs_key",
181
+ "claim_ineligible",
182
+ "claim_unavailable",
183
+ "lease_lost",
184
+ "executor_revoked",
185
+ "executor_unauthorized",
186
+ "oidc_bad_issuer",
187
+ "oidc_repo_not_enrolled",
188
+ "oidc_ref_not_allowed",
189
+ "oidc_pool_flag_off",
190
+ "oidc_unavailable",
191
+ "api_unavailable",
192
+ ];
193
+ /** Under --fail-mode open, only these may be ridden through, and only once a verified bundle is held (34.12 (2)). */
194
+ export const RUNNER_OPEN_MODE_TOLERATED = [
195
+ "bundle_unavailable",
196
+ "job_unavailable",
197
+ "api_unavailable",
198
+ ];
199
+ export const RUNNER_MERGE_STRATEGIES = ["external", "merge_on_green"];
200
+ // ---- Pool claim answer (rulings 34.03 (3), 34.05.1 (4)) -------------------------------------
201
+ /**
202
+ * The fields a 200 claim answer carries exactly when the session is a pool session: the charter's
203
+ * contract_sha256 and contract_version, and the effective cap. A homed claim's answer carries none.
204
+ */
205
+ export const POOL_CLAIM_FIELDS = ["contract_sha256", "contract_version", "cap"];
206
+ const HEX64_RE = /^[0-9a-f]{64}$/;
207
+ /** Whether a 200 claim answer's pool fields match `pool` (other keys are not judged here). */
208
+ export function poolClaimFieldsOk(body, pool) {
209
+ if (!pool)
210
+ return POOL_CLAIM_FIELDS.every((k) => !(k in body));
211
+ return (typeof body.contract_sha256 === "string" &&
212
+ HEX64_RE.test(body.contract_sha256) &&
213
+ Number.isInteger(body.contract_version) &&
214
+ body.contract_version >= 1 &&
215
+ capOk(body.cap));
216
+ }
217
+ // ---- Waits (ruling 34.06) -------------------------------------------------------------------
218
+ /**
219
+ * agent_sessions.wait_ref, closed per PARKED_ONLY_WAIT_REASONS value (34.06 (2)): commitments only.
220
+ * repo_id is GitHub's numeric repository.id, a positive integer (ruling 34.14 (6)).
221
+ */
222
+ export const WAIT_REF_KEYS = Object.freeze({
223
+ ci: ["repo_id", "head_sha"],
224
+ question: ["approval_id"],
225
+ budget: ["approval_id"],
226
+ });
227
+ const HEX40_RE = /^[0-9a-f]{40}$/;
228
+ /** Whether `ref` is exactly the wait_ref shape for `reason`. */
229
+ export function waitRefOk(reason, ref) {
230
+ if (!Object.prototype.hasOwnProperty.call(WAIT_REF_KEYS, reason))
231
+ return false;
232
+ if (ref === null || typeof ref !== "object" || Array.isArray(ref))
233
+ return false;
234
+ const r = ref;
235
+ const want = WAIT_REF_KEYS[reason];
236
+ if (Object.keys(r).length !== want.length || !want.every((k) => k in r))
237
+ return false;
238
+ if (reason === "ci")
239
+ return (Number.isSafeInteger(r.repo_id) &&
240
+ r.repo_id > 0 &&
241
+ typeof r.head_sha === "string" &&
242
+ HEX40_RE.test(r.head_sha));
243
+ return typeof r.approval_id === "string" && UUID_RE.test(r.approval_id);
244
+ }
245
+ /** durable_clear_wait answers (34.06 (4)). */
246
+ export const CLEAR_WAIT_OUTCOMES = ["cleared", "stale_ref", "already_clear"];
247
+ /** durable_ready_sessions p_limit and exec_ready_list ?limit= range (34.03 (3)). */
248
+ export const READY_SESSIONS_LIMIT_MIN = 1;
249
+ export const READY_SESSIONS_LIMIT_MAX = 50;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Contract ciphertext envelope v1 and the charter commitment schema (C18-R01..R03; BACKBONE
3
+ * amendment 36; r3 U05). API only: no other repo decrypts.
4
+ *
5
+ * contract_ciphertext = "v1." + b64url(iv, 12 bytes) + "." + b64url(ciphertext || 16-byte tag)
6
+ * AES-256-GCM, per-session 32-byte DEK, random IV per write
7
+ * AAD = UTF-8 "durable-contract:v1:<session_id>:<charter_version>"
8
+ * plaintext = canonicalJson({statement, requirements, allowed_paths, forbidden_paths}), plus
9
+ * goal_id, work_card and shape when the seal carries them (amendment 55)
10
+ * wrapped_data_key = encryptBlob(dekWrapInput(DEK)) under the SESSION_COOKIE_KEY keyring (api)
11
+ * statement_hash = sha256(canonicalJson(statement)); requirements_hash = sha256(canonicalJson(requirements))
12
+ */
13
+ export declare const ENVELOPE_VERSION = "v1";
14
+ export declare const CIPHER_KEY_REFS: readonly ["mnemom"];
15
+ export declare const DEK_BYTES = 32;
16
+ export declare const IV_BYTES = 12;
17
+ export declare const TAG_BYTES = 16;
18
+ export interface Contract {
19
+ statement: string;
20
+ requirements: string[];
21
+ allowed_paths: string[];
22
+ forbidden_paths: string[];
23
+ /** Amendment 55: the seal's goal_id, work_card and shape ride the ciphertext, present only when sealed. */
24
+ goal_id?: string;
25
+ work_card?: true;
26
+ shape?: "duty";
27
+ }
28
+ /** The Contract's optional keys (amendment 55); absent unless the gateway seal carried them. */
29
+ export declare const CONTRACT_OPTIONAL_KEYS: readonly ["goal_id", "work_card", "shape"];
30
+ export declare function contractAad(sessionId: string, charterVersion: number): string;
31
+ /** Validate a submitted contract; null when malformed or over the statement limit. */
32
+ export declare function parseContract(raw: unknown): Contract | null;
33
+ export declare function contractPlaintext(c: Contract): string;
34
+ export declare function statementHash(statement: string): Promise<string>;
35
+ export declare function requirementsHash(requirements: readonly string[]): Promise<string>;
36
+ /** What encryptBlob wraps: base64url of the raw DEK (so wrapped_data_key never decodes to 32 raw bytes). */
37
+ export declare function dekWrapInput(dek: Uint8Array): string;
38
+ export declare function dekFromWrapInput(text: string): Uint8Array | null;
39
+ export declare function newDek(random?: (n: number) => Uint8Array): Uint8Array;
40
+ /** Seal a contract. `random` is injectable for golden vectors only; production uses getRandomValues. */
41
+ export declare function sealContract(dek: Uint8Array, sessionId: string, charterVersion: number, contract: Contract, random?: (n: number) => Uint8Array): Promise<string>;
42
+ export declare function parseEnvelope(text: string): {
43
+ iv: Uint8Array;
44
+ ct: Uint8Array;
45
+ } | null;
46
+ /** Open an envelope; null on a malformed envelope, wrong key, wrong session or wrong version (AAD). */
47
+ export declare function openContract(dek: Uint8Array, sessionId: string, charterVersion: number, envelope: string): Promise<Contract | null>;
48
+ export declare const COMMITMENT_KEYS: readonly ["statement_hash", "requirements_hash", "budget_usd", "per_wake_cap_usd", "max_wakes_per_day", "max_turns", "active_time_limit_s", "pins", "tool_classes", "launch_spec", "mode", "stall_turns", "contract_hash"];
49
+ /** The gateway's sealed-contract modes (MNE-8199); committed as `mode` by amendment 55. */
50
+ export declare const CONTRACT_MODE_VALUES: readonly ["nudge", "enforce"];
51
+ export declare const TOOL_CLASS_VALUES: readonly ["input_dependent", "safe", "idempotent"];
52
+ /**
53
+ * Charter pins (BACKBONE A3, rulings U13, C07-R23): card_content_hash is the agent's live /state
54
+ * content_hash read at lock; policy_engine_major is the API's policy-engine major at lock. Both
55
+ * required, never empty, inside the charter preimage.
56
+ */
57
+ export declare const PIN_KEYS: readonly ["card_content_hash", "policy_engine_major"];
58
+ /** Validate a charter commitment object (keys a subset of COMMITMENT_KEYS; no text values). */
59
+ export declare function isValidCommitment(raw: unknown): boolean;
60
+ /** M1 accepts only input_dependent tool classes (safe/idempotent -> 422 durable_unsupported {feature:'tool_classes'}). */
61
+ export declare function toolClassesSupportedM1(toolClasses: Readonly<Record<string, string>> | undefined): boolean;
62
+ /**
63
+ * The charter row preimage. hash = sha256(canonicalJson(charterPreimage(row))); v(1).prev_hash =
64
+ * GENESIS_PREV_HASH (64 zeros) and v(n).prev_hash = v(n-1).hash. The preimage is exactly these
65
+ * fields (canonicalJson sorts keys):
66
+ * v CHARTER_PREIMAGE_VERSION (1)
67
+ * session_id the session uuid, lowercase text
68
+ * version the charter version, integer >= 1
69
+ * prev_hash 64 lowercase hex
70
+ * charter the commitment object (isValidCommitment; pins included)
71
+ * created_at canonicalEventTs(created_at): UTC, "T", 6 fraction digits, "Z" (a Postgres
72
+ * timestamptz text such as "2026-10-16 12:00:00.123+00" canonicalises the same).
73
+ * Amendment 55: v1's created_at IS the original seal's sealed_at (T0, the gateway's
74
+ * first sealed request), never the lock time: build it with charterV1CreatedAt. Every
75
+ * reader that reports a session's sealed_at reads v1's created_at. v(n>1)'s created_at
76
+ * is the amend time and never changes sealed_at.
77
+ * Every other agent_session_charters column is outside it (CHARTER_HASH_EXCLUDED_COLUMNS), so a KEK
78
+ * re-wrap (wrapped_data_key changes) and the contract purge (contract_ciphertext nulled,
79
+ * contract_purge_after stamped) leave every hash and agent_sessions.charter_hash unchanged.
80
+ */
81
+ export declare const CHARTER_PREIMAGE_VERSION = 1;
82
+ export declare const CHARTER_PREIMAGE_FIELDS: readonly ["v", "session_id", "version", "prev_hash", "charter", "created_at"];
83
+ export declare const CHARTER_HASH_EXCLUDED_COLUMNS: readonly ["hash", "contract_ciphertext", "wrapped_data_key", "cipher_key_ref", "contract_purge_after", "signature"];
84
+ export interface CharterPreimageInput {
85
+ session_id: string;
86
+ version: number;
87
+ prev_hash: string;
88
+ charter: Record<string, unknown>;
89
+ created_at: string;
90
+ }
91
+ /**
92
+ * Build the preimage from a charter row. Extra row columns (the excluded ones) are ignored. Throws on
93
+ * a bad version, a malformed prev_hash, a version-1 row that does not chain from genesis, or an
94
+ * invalid commitment.
95
+ */
96
+ export declare function charterPreimage(row: CharterPreimageInput): Record<string, unknown>;
97
+ /**
98
+ * Charter v1's created_at from the gateway seal's sealed_at (amendment 55). The seal may carry any
99
+ * ISO-8601 instant (UTC, or an offset such as "-07:00", at millisecond precision); the result is the same instant in
100
+ * canonicalEventTs form. Throws on text that is not an instant.
101
+ */
102
+ export declare function charterV1CreatedAt(sealedAt: string): string;
103
+ export declare function charterHash(row: CharterPreimageInput): Promise<string>;