@mnemom/mnemom 0.17.39-next.0 → 0.17.39-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-run.js +2 -0
- package/dist/commands/auth.d.ts +46 -1
- package/dist/commands/auth.js +51 -2
- package/dist/durable/turn-chain.js +3 -1
- package/dist/host/inbox-delivery.js +3 -1
- package/dist/index.js +3 -2
- package/dist/lib/api.d.ts +19 -0
- package/dist/lib/api.js +8 -0
- package/dist/lib/runner/oidc.d.ts +6 -1
- package/dist/lib/runner/oidc.js +8 -2
- package/dist/vendor/durable-contract/index.js +168 -12
- package/dist/vendor/shared/durable-contract/codes.d.ts +13 -0
- package/dist/vendor/shared/durable-contract/codes.js +10 -0
- package/dist/vendor/shared/durable-contract/doors.d.ts +88 -4
- package/dist/vendor/shared/durable-contract/doors.js +142 -5
- package/dist/vendor/shared/durable-contract/events.d.ts +2 -1
- package/dist/vendor/shared/durable-contract/events.js +10 -1
- package/dist/vendor/shared/durable-contract/freeze-record.d.ts +25 -5
- package/dist/vendor/shared/durable-contract/freeze-record.js +25 -3
- package/dist/vendor/shared/durable-contract/routes.d.ts +23 -1
- package/dist/vendor/shared/durable-contract/routes.js +34 -1
- package/dist/vendor/shared/durable-contract/schema.d.ts +3 -3
- package/dist/vendor/shared/durable-contract/schema.js +7 -4
- package/dist/vendor/shared/durable-contract/states.d.ts +16 -3
- package/dist/vendor/shared/durable-contract/states.js +20 -1
- package/package.json +1 -1
|
@@ -72,6 +72,8 @@ export async function agentRunCommand(flags, deps) {
|
|
|
72
72
|
apiUrl: deps.apiUrl,
|
|
73
73
|
requestUrl: plan.credential.requestUrl,
|
|
74
74
|
requestToken: plan.credential.requestToken,
|
|
75
|
+
// Amendment 66: set by the action from the wake-up's adopt-ticket input; empty sends none.
|
|
76
|
+
adoptTicket: deps.env.MNEMOM_ADOPT_TICKET?.trim() || null,
|
|
75
77
|
});
|
|
76
78
|
if (!ex.ok) {
|
|
77
79
|
// No job is held yet: fail closed whatever --fail-mode says (34.12 (6)).
|
package/dist/commands/auth.d.ts
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mnemom whoami --json`: who is logged in, and which org is active, as ONE
|
|
3
|
+
* JSON object for a program to read. It carries identity only, never a
|
|
4
|
+
* credential: no access or refresh token, no API key, no scope string.
|
|
5
|
+
*
|
|
6
|
+
* {"logged_in": bool, "user_id": str|null, "email": str|null,
|
|
7
|
+
* "key_id": str|null, "org_id": str|null,
|
|
8
|
+
* "active_org": {"org_id", "slug", "name"}|null, "expires_at": ISO|null,
|
|
9
|
+
* "api_url": the API origin this identity was resolved against}
|
|
10
|
+
*
|
|
11
|
+
* A person (an OAuth login) is user_id + email, read from GET /v1/auth/session.
|
|
12
|
+
* An API key is key_id + org_id (its own org), read from GET
|
|
13
|
+
* /v1/api-keys/whoami; its user_id is always null, because a key's owning
|
|
14
|
+
* person is not the caller and a reader must key a key on key_id, never on
|
|
15
|
+
* that person. When the identity read fails, user_id, email, key_id and org_id
|
|
16
|
+
* are null: never a stale stored value.
|
|
17
|
+
*
|
|
18
|
+
* api_url is getApiUrl() in this process (--api / MNEMOM_API_URL > MNEMOM_RING
|
|
19
|
+
* > MNEMOM_ENV). Identities never cross environments (test, us-1 and
|
|
20
|
+
* production each have their own), so a reader pins one origin and refuses a
|
|
21
|
+
* whoami whose api_url is not it.
|
|
22
|
+
*
|
|
23
|
+
* A reader beside the CLI must never read ~/.mnemom/auth.json or call the API
|
|
24
|
+
* with the stored token itself: the CLI refreshes and rotates its tokens under
|
|
25
|
+
* a lock (MNE-9232), and a second token handler would race that refresh. This
|
|
26
|
+
* is the read such a reader uses instead (develop's install and every acting
|
|
27
|
+
* develop verb, which take their operator and tenant from the login).
|
|
28
|
+
*/
|
|
29
|
+
export interface WhoamiJson {
|
|
30
|
+
logged_in: boolean;
|
|
31
|
+
user_id: string | null;
|
|
32
|
+
email: string | null;
|
|
33
|
+
key_id: string | null;
|
|
34
|
+
org_id: string | null;
|
|
35
|
+
active_org: {
|
|
36
|
+
org_id: string;
|
|
37
|
+
slug: string;
|
|
38
|
+
name: string | null;
|
|
39
|
+
} | null;
|
|
40
|
+
expires_at: string | null;
|
|
41
|
+
api_url: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function whoamiJson(): Promise<WhoamiJson>;
|
|
1
44
|
export declare function loginCommand(options?: {
|
|
2
45
|
noBrowser?: boolean;
|
|
3
46
|
}): Promise<void>;
|
|
4
47
|
export declare function logoutCommand(): Promise<void>;
|
|
5
|
-
export declare function whoamiCommand(
|
|
48
|
+
export declare function whoamiCommand(options?: {
|
|
49
|
+
json?: boolean;
|
|
50
|
+
}): Promise<void>;
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
import { getAuthInfo, clearAuthTokens, loginWithBrowser, loginWithDeviceFlow, resolveAuth, } from "../lib/auth.js";
|
|
2
|
-
import { getMe } from "../lib/api.js";
|
|
2
|
+
import { getApiKeyWhoami, getMe, getSession } from "../lib/api.js";
|
|
3
|
+
import { getActiveOrg } from "../lib/cli-config.js";
|
|
4
|
+
import { getApiUrl } from "../lib/config.js";
|
|
3
5
|
import { fmt } from "../lib/format.js";
|
|
6
|
+
export async function whoamiJson() {
|
|
7
|
+
const active = getActiveOrg();
|
|
8
|
+
const active_org = active
|
|
9
|
+
? { org_id: active.org_id, slug: active.slug, name: active.name ?? null }
|
|
10
|
+
: null;
|
|
11
|
+
const out = {
|
|
12
|
+
logged_in: false,
|
|
13
|
+
user_id: null,
|
|
14
|
+
email: null,
|
|
15
|
+
key_id: null,
|
|
16
|
+
org_id: null,
|
|
17
|
+
active_org,
|
|
18
|
+
expires_at: null,
|
|
19
|
+
api_url: getApiUrl(),
|
|
20
|
+
};
|
|
21
|
+
const cred = await resolveAuth();
|
|
22
|
+
if (cred.type === "none")
|
|
23
|
+
return out;
|
|
24
|
+
if (cred.type === "api-key") {
|
|
25
|
+
// A key is keyed on its own id and org, never on its owner's user id.
|
|
26
|
+
const key = await getApiKeyWhoami().catch(() => null);
|
|
27
|
+
return { ...out, logged_in: true, key_id: key?.key_id ?? null, org_id: key?.org_id ?? null };
|
|
28
|
+
}
|
|
29
|
+
if (!getAuthInfo())
|
|
30
|
+
return out;
|
|
31
|
+
// The OAuth token carries no identity: ask the API (GET /v1/auth/session, a
|
|
32
|
+
// pure read, unlike /v1/auth/me's billing and SSO JIT writes), which goes
|
|
33
|
+
// through the CLI's own refresh. A failed read leaves the identity null: a
|
|
34
|
+
// stored legacy value could belong to another session or environment.
|
|
35
|
+
const session = await getSession().catch(() => null);
|
|
36
|
+
const me = session ? { user_id: session.user.id, email: session.user.email ?? null } : null;
|
|
37
|
+
// Read the grant after that call: a refresh inside it moves expiresAt.
|
|
38
|
+
const auth = getAuthInfo();
|
|
39
|
+
if (!auth)
|
|
40
|
+
return out;
|
|
41
|
+
return {
|
|
42
|
+
...out,
|
|
43
|
+
logged_in: true,
|
|
44
|
+
user_id: me?.user_id ?? null,
|
|
45
|
+
email: me?.email ?? null,
|
|
46
|
+
expires_at: new Date(auth.expiresAt * 1000).toISOString(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
4
49
|
export async function loginCommand(options = {}) {
|
|
5
50
|
try {
|
|
6
51
|
// --no-browser → RFC 8628 device flow (headless / SSH / no local browser).
|
|
@@ -53,7 +98,11 @@ export async function logoutCommand() {
|
|
|
53
98
|
clearAuthTokens();
|
|
54
99
|
console.log(fmt.success("Logged out."));
|
|
55
100
|
}
|
|
56
|
-
export async function whoamiCommand() {
|
|
101
|
+
export async function whoamiCommand(options = {}) {
|
|
102
|
+
if (options.json) {
|
|
103
|
+
console.log(JSON.stringify(await whoamiJson()));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
57
106
|
const cred = await resolveAuth();
|
|
58
107
|
if (cred.type === "none") {
|
|
59
108
|
console.log("\nNot logged in. Run `mnemom login` to authenticate.\n");
|
|
@@ -86,7 +86,9 @@ export function entryProducer(e) {
|
|
|
86
86
|
return typeof p === "string" && TURN_PRODUCER_RE.test(p) ? p : undefined;
|
|
87
87
|
}
|
|
88
88
|
/** Claude Code's open tag for a bracketed paste, which may lead a pasted prompt's text. */
|
|
89
|
-
|
|
89
|
+
// Claude Code may record the paste after blank lines ("\n\n<pasted_content id=...>"); a delivery the marker
|
|
90
|
+
// misses there is never confirmed and gets pasted again (seen live: 4 pastes of one message).
|
|
91
|
+
const PASTE_OPEN_RE = /^\n*<pasted_content id="[^"\n]{0,128}">\n?/;
|
|
90
92
|
/**
|
|
91
93
|
* The inbox sha an entry answers (S1 amendment 60): the `[mnemom inbox <sha>]` marker on the first
|
|
92
94
|
* line of the entry's first text (after Claude Code's paste open tag, as the host daemon delivers by
|
|
@@ -72,7 +72,9 @@ export const HANDLED_MAX = 32;
|
|
|
72
72
|
/** claude's input line, and the footer it shows while a turn runs. */
|
|
73
73
|
const PROMPT_MARK = "❯";
|
|
74
74
|
const RUNNING_RE = /esc to interrupt/i;
|
|
75
|
-
|
|
75
|
+
// Claude Code may record the paste after blank lines ("\n\n<pasted_content id=...>"); a delivery the marker
|
|
76
|
+
// misses there is never confirmed and gets pasted again (seen live: 4 pastes of one message).
|
|
77
|
+
const PASTE_OPEN_RE = /^\n*<pasted_content id="[^"\n]{0,128}">\n?/;
|
|
76
78
|
function firstText(r) {
|
|
77
79
|
const c = r.message?.content;
|
|
78
80
|
if (typeof c === "string")
|
package/dist/index.js
CHANGED
|
@@ -1976,9 +1976,10 @@ program
|
|
|
1976
1976
|
program
|
|
1977
1977
|
.command("whoami")
|
|
1978
1978
|
.description("Show current authentication status")
|
|
1979
|
-
.
|
|
1979
|
+
.option("--json", "Print who is logged in as one JSON object: {logged_in, user_id, email, active_org, expires_at} (never a token)")
|
|
1980
|
+
.action(async (options) => {
|
|
1980
1981
|
try {
|
|
1981
|
-
await whoamiCommand();
|
|
1982
|
+
await whoamiCommand({ json: options.json });
|
|
1982
1983
|
}
|
|
1983
1984
|
catch (error) {
|
|
1984
1985
|
console.error("Error:", error instanceof Error ? error.message : error);
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -426,6 +426,25 @@ export interface MeResponse {
|
|
|
426
426
|
} | null;
|
|
427
427
|
}
|
|
428
428
|
export declare function getMe(): Promise<MeResponse>;
|
|
429
|
+
/** Who the credential belongs to — `GET /v1/auth/session`. A pure read for a
|
|
430
|
+
* bearer (no billing-account ensure and no SSO JIT provisioning, which
|
|
431
|
+
* `GET /v1/auth/me` runs on every call), so an identity check changes nothing. */
|
|
432
|
+
export interface SessionResponse {
|
|
433
|
+
user: {
|
|
434
|
+
id: string;
|
|
435
|
+
email?: string | null;
|
|
436
|
+
};
|
|
437
|
+
method?: string;
|
|
438
|
+
}
|
|
439
|
+
export declare function getSession(): Promise<SessionResponse>;
|
|
440
|
+
/** What an API key is — `GET /v1/api-keys/whoami` (ADR-049). A read; the key's
|
|
441
|
+
* own id and org, which is how a reader keys a key caller. */
|
|
442
|
+
export interface ApiKeyWhoamiResponse {
|
|
443
|
+
key_id: string | null;
|
|
444
|
+
org_id: string | null;
|
|
445
|
+
auth_method?: string;
|
|
446
|
+
}
|
|
447
|
+
export declare function getApiKeyWhoami(): Promise<ApiKeyWhoamiResponse>;
|
|
429
448
|
/**
|
|
430
449
|
* The org's Mnemom Units (MU) balance — `GET /v1/billing/mu` (the frozen mu
|
|
431
450
|
* v0.1 balance, values as decimal strings). Amounts come in both whole MU
|
package/dist/lib/api.js
CHANGED
|
@@ -440,6 +440,14 @@ export async function getMyPersonalOrg() {
|
|
|
440
440
|
export async function getMe() {
|
|
441
441
|
return gFetch("/v1/auth/me", {}, { fallback: "Could not read your identity" });
|
|
442
442
|
}
|
|
443
|
+
export async function getSession() {
|
|
444
|
+
return gFetch("/v1/auth/session", {}, { fallback: "Could not read your identity" });
|
|
445
|
+
}
|
|
446
|
+
export async function getApiKeyWhoami() {
|
|
447
|
+
return gFetch("/v1/api-keys/whoami", {}, {
|
|
448
|
+
fallback: "Could not read your API key's identity",
|
|
449
|
+
});
|
|
450
|
+
}
|
|
443
451
|
export async function getRecordTotals(orgId, lineageKey, signal) {
|
|
444
452
|
return gFetch(`/v1/orgs/${encodeURIComponent(orgId)}/record/totals?lineage_key=${encodeURIComponent(lineageKey)}`, signal ? { signal } : {}, { notFoundLabel: "Record totals", fallback: "Could not read record totals" });
|
|
445
453
|
}
|
|
@@ -30,10 +30,15 @@ export declare function actionsIdToken(fetch: FetchFn, requestUrl: string, reque
|
|
|
30
30
|
ok: false;
|
|
31
31
|
detail: string;
|
|
32
32
|
}>;
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Fetch the ID token and exchange it for a one-lease executor key. `adoptTicket` (Amendment 66) is
|
|
35
|
+
* the ticket the api's wake-up passed this run as the adopt-ticket input; it rides in the body
|
|
36
|
+
* beside the token, and like the token it never reaches a log line or an outcome.
|
|
37
|
+
*/
|
|
34
38
|
export declare function exchangeOidc(opts: {
|
|
35
39
|
fetch: FetchFn;
|
|
36
40
|
apiUrl: string;
|
|
37
41
|
requestUrl: string;
|
|
38
42
|
requestToken: string;
|
|
43
|
+
adoptTicket?: string | null;
|
|
39
44
|
}): Promise<OidcExchange>;
|
package/dist/lib/runner/oidc.js
CHANGED
|
@@ -54,7 +54,11 @@ export async function actionsIdToken(fetch, requestUrl, requestToken) {
|
|
|
54
54
|
return { ok: false, detail: `ID token request failed: ${e.message}` };
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Fetch the ID token and exchange it for a one-lease executor key. `adoptTicket` (Amendment 66) is
|
|
59
|
+
* the ticket the api's wake-up passed this run as the adopt-ticket input; it rides in the body
|
|
60
|
+
* beside the token, and like the token it never reaches a log line or an outcome.
|
|
61
|
+
*/
|
|
58
62
|
export async function exchangeOidc(opts) {
|
|
59
63
|
const id = await actionsIdToken(opts.fetch, opts.requestUrl, opts.requestToken);
|
|
60
64
|
if (!id.ok)
|
|
@@ -65,7 +69,9 @@ export async function exchangeOidc(opts) {
|
|
|
65
69
|
res = await opts.fetch(`${base}${routePath("exec_oidc_exchange")}`, {
|
|
66
70
|
method: "POST",
|
|
67
71
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
68
|
-
body: JSON.stringify(
|
|
72
|
+
body: JSON.stringify(opts.adoptTicket
|
|
73
|
+
? { oidc_token: id.token, adopt_ticket: opts.adoptTicket }
|
|
74
|
+
: { oidc_token: id.token }),
|
|
69
75
|
});
|
|
70
76
|
}
|
|
71
77
|
catch (e) {
|
|
@@ -238,12 +238,20 @@ var WAIT_REASONS = [
|
|
|
238
238
|
"mnemom_unavailable",
|
|
239
239
|
"ci",
|
|
240
240
|
"question",
|
|
241
|
-
"budget"
|
|
241
|
+
"budget",
|
|
242
|
+
"awaiting_issue_run",
|
|
243
|
+
"repo_arm_unreadable"
|
|
242
244
|
];
|
|
243
245
|
var PARKED_ONLY_WAIT_REASONS = [
|
|
244
246
|
"ci",
|
|
245
247
|
"question",
|
|
246
|
-
"budget"
|
|
248
|
+
"budget",
|
|
249
|
+
"awaiting_issue_run",
|
|
250
|
+
"repo_arm_unreadable"
|
|
251
|
+
];
|
|
252
|
+
var DISPATCH_PARK_WAIT_REASONS = [
|
|
253
|
+
"awaiting_issue_run",
|
|
254
|
+
"repo_arm_unreadable"
|
|
247
255
|
];
|
|
248
256
|
function isSessionState(v) {
|
|
249
257
|
return typeof v === "string" && SESSION_STATES.includes(v);
|
|
@@ -1066,6 +1074,7 @@ var CLAIM_UNAVAILABLE_CAUSES = [
|
|
|
1066
1074
|
"lease_cap_config"
|
|
1067
1075
|
];
|
|
1068
1076
|
var SEAL_REPO_MISMATCH_CAUSES = ["no_repo_claim", "no_seal_repo", "repo_mismatch"];
|
|
1077
|
+
var ADOPT_REFUSED_CAUSES = ["no_parked_seal", "not_parked"];
|
|
1069
1078
|
var UNSUPPORTED_FEATURES = [
|
|
1070
1079
|
"tool_classes",
|
|
1071
1080
|
"launch_spec_change",
|
|
@@ -1179,6 +1188,9 @@ var DURABLE_CODES = {
|
|
|
1179
1188
|
// durable_claim_ineligible reason: the session is claimable, only not by this executor, and a
|
|
1180
1189
|
// runner never skips past it to another session. cause is a SEAL_REPO_MISMATCH_CAUSES value.
|
|
1181
1190
|
seal_repo_mismatch: { status: 403, surfaces: ["api"], fields: ["cause"] },
|
|
1191
|
+
// S1 amendment 64 (mnemom-test#1336): exec_adopt found nothing it may unpark for this run. Nothing
|
|
1192
|
+
// is written. cause is an ADOPT_REFUSED_CAUSES value.
|
|
1193
|
+
adopt_refused: { status: 409, surfaces: ["api"], fields: ["cause"] },
|
|
1182
1194
|
// ---- api journal (C10-R0 (i), (j), (k)) ----
|
|
1183
1195
|
/** Lost CAS race on (session_id, seq). */
|
|
1184
1196
|
durable_append_conflict: { status: 409, surfaces: ["api"], fields: ["tip_seq"] },
|
|
@@ -2372,9 +2384,62 @@ var OIDC_EXCHANGE_REFUSALS = [
|
|
|
2372
2384
|
"bad_issuer",
|
|
2373
2385
|
"repo_not_enrolled",
|
|
2374
2386
|
"ref_not_allowed",
|
|
2375
|
-
"pool_flag_off"
|
|
2387
|
+
"pool_flag_off",
|
|
2388
|
+
"adopt_ticket_invalid",
|
|
2389
|
+
"token_replayed",
|
|
2390
|
+
"run_already_exchanged"
|
|
2376
2391
|
];
|
|
2392
|
+
var OIDC_EXCHANGE_RUN_CLAIMS = ["jti", "run_id", "run_attempt"];
|
|
2393
|
+
var OIDC_JTI_MAX = 200;
|
|
2394
|
+
var OIDC_RUN_NUMBER_RE = /^[1-9][0-9]{0,15}$/;
|
|
2395
|
+
var OIDC_EXCHANGE_RETENTION_DAYS = 35;
|
|
2396
|
+
function oidcRunClaimsOk(claims) {
|
|
2397
|
+
const { jti, run_id, run_attempt } = claims;
|
|
2398
|
+
return typeof jti === "string" && jti.length >= 1 && jti.length <= OIDC_JTI_MAX && typeof run_id === "string" && OIDC_RUN_NUMBER_RE.test(run_id) && typeof run_attempt === "string" && OIDC_RUN_NUMBER_RE.test(run_attempt);
|
|
2399
|
+
}
|
|
2377
2400
|
var OIDC_EXCHANGE_AUDIENCE = "mnemom-executor";
|
|
2401
|
+
var ADOPT_TICKET_INPUT = "adopt-ticket";
|
|
2402
|
+
var WAKEUP_SESSION_INPUT = "session-id";
|
|
2403
|
+
var ADOPT_TICKET_RE = /^mnm_at_[A-Za-z0-9_-]{43}$/;
|
|
2404
|
+
var ADOPT_TICKET_TTL_S = 900;
|
|
2405
|
+
var OIDC_EXCHANGE_BODY_KEYS = ["oidc_token", "adopt_ticket"];
|
|
2406
|
+
var OIDC_TOKEN_MAX = 8192;
|
|
2407
|
+
var OIDC_WORKFLOW_ENV = "DISPATCH_WAKEUP_WORKFLOW";
|
|
2408
|
+
var OIDC_WORKFLOW_FILE_RE = /^[A-Za-z0-9_.-]{1,100}\.ya?ml$/;
|
|
2409
|
+
var OIDC_WORKFLOW_SET_ENV = "DURABLE_OIDC_WORKFLOWS";
|
|
2410
|
+
var OIDC_WORKFLOW_SET_MAX = 8;
|
|
2411
|
+
function adoptTicketOk(t) {
|
|
2412
|
+
return typeof t === "string" && ADOPT_TICKET_RE.test(t);
|
|
2413
|
+
}
|
|
2414
|
+
function oidcExchangeBodyOk(v) {
|
|
2415
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
2416
|
+
const o = v;
|
|
2417
|
+
const keys = Object.keys(o);
|
|
2418
|
+
if (keys.some((k) => !OIDC_EXCHANGE_BODY_KEYS.includes(k))) return false;
|
|
2419
|
+
if (typeof o.oidc_token !== "string" || o.oidc_token === "" || o.oidc_token.length > OIDC_TOKEN_MAX)
|
|
2420
|
+
return false;
|
|
2421
|
+
return !("adopt_ticket" in o) || typeof o.adopt_ticket === "string";
|
|
2422
|
+
}
|
|
2423
|
+
function oidcPinnedWorkflow(envValue) {
|
|
2424
|
+
const wf = envValue?.trim() ?? "";
|
|
2425
|
+
return OIDC_WORKFLOW_FILE_RE.test(wf) ? wf : null;
|
|
2426
|
+
}
|
|
2427
|
+
function oidcWorkflowSet(setValue, pinValue) {
|
|
2428
|
+
if (setValue === void 0) {
|
|
2429
|
+
const pin = oidcPinnedWorkflow(pinValue);
|
|
2430
|
+
return pin === null ? null : [pin];
|
|
2431
|
+
}
|
|
2432
|
+
const names = setValue.split(",").map((n) => n.trim());
|
|
2433
|
+
if (names.some((n) => !OIDC_WORKFLOW_FILE_RE.test(n) || n.includes(".."))) return null;
|
|
2434
|
+
const set = [...new Set(names)];
|
|
2435
|
+
return set.length > OIDC_WORKFLOW_SET_MAX ? null : set;
|
|
2436
|
+
}
|
|
2437
|
+
function jobWorkflowRefOk(jobWorkflowRef, repository, workflowFile, defaultBranch) {
|
|
2438
|
+
return typeof jobWorkflowRef === "string" && jobWorkflowRef === `${repository}/.github/workflows/${workflowFile}@refs/heads/${defaultBranch}`;
|
|
2439
|
+
}
|
|
2440
|
+
function jobWorkflowRefInSet(jobWorkflowRef, repository, workflowFiles, defaultBranch) {
|
|
2441
|
+
return workflowFiles.some((f2) => jobWorkflowRefOk(jobWorkflowRef, repository, f2, defaultBranch));
|
|
2442
|
+
}
|
|
2378
2443
|
var ORG_POLICY_LIMIT_KEYS = ["per_session_budget_usd", "live_lease_cap"];
|
|
2379
2444
|
var LIVE_LEASE_CAP_MIN = 1;
|
|
2380
2445
|
var LIVE_LEASE_CAP_MAX = 1e3;
|
|
@@ -2408,14 +2473,15 @@ var CREATE_READY_SESSION_REFUSALS = [
|
|
|
2408
2473
|
// 34.10.1 (4): the api-built charter v1 or its envelope does not match the seal; nothing written
|
|
2409
2474
|
"charter_mismatch"
|
|
2410
2475
|
];
|
|
2411
|
-
var CREATE_READY_SESSION_OUTCOMES = ["created", "existing", "refused"];
|
|
2476
|
+
var CREATE_READY_SESSION_OUTCOMES = ["created", "existing", "refused", "parked"];
|
|
2412
2477
|
function isUserCreator(createdBy) {
|
|
2413
2478
|
return typeof createdBy === "string" && createdBy !== "" && !createdBy.includes(":");
|
|
2414
2479
|
}
|
|
2415
2480
|
var CREATE_READY_SESSION_ANSWERS = Object.freeze({
|
|
2416
2481
|
created: ["outcome", "session_id"],
|
|
2417
2482
|
existing: ["outcome", "session_id"],
|
|
2418
|
-
refused: ["outcome", "reason"]
|
|
2483
|
+
refused: ["outcome", "reason"],
|
|
2484
|
+
parked: ["outcome", "session_id", "wait_reason"]
|
|
2419
2485
|
});
|
|
2420
2486
|
function createReadySessionAnswerOk(v) {
|
|
2421
2487
|
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
@@ -2424,7 +2490,11 @@ function createReadySessionAnswerOk(v) {
|
|
|
2424
2490
|
return false;
|
|
2425
2491
|
const keys = CREATE_READY_SESSION_ANSWERS[a.outcome];
|
|
2426
2492
|
if (Object.keys(a).length !== keys.length || !keys.every((k) => k in a)) return false;
|
|
2427
|
-
|
|
2493
|
+
if (a.outcome === "refused")
|
|
2494
|
+
return CREATE_READY_SESSION_REFUSALS.includes(a.reason);
|
|
2495
|
+
if (a.outcome === "parked" && !DISPATCH_PARK_WAIT_REASONS.includes(a.wait_reason))
|
|
2496
|
+
return false;
|
|
2497
|
+
return typeof a.session_id === "string" && UUID_RE.test(a.session_id);
|
|
2428
2498
|
}
|
|
2429
2499
|
function sealIdOk(sealId) {
|
|
2430
2500
|
if (!UUID_RE.test(sealId)) throw new RangeError(`seal id must be a lowercase uuid: ${sealId}`);
|
|
@@ -2501,7 +2571,11 @@ var RUNNER_REFUSED_REASONS = [
|
|
|
2501
2571
|
"oidc_ref_not_allowed",
|
|
2502
2572
|
"oidc_pool_flag_off",
|
|
2503
2573
|
"oidc_unavailable",
|
|
2504
|
-
"api_unavailable"
|
|
2574
|
+
"api_unavailable",
|
|
2575
|
+
"oidc_adopt_ticket_invalid",
|
|
2576
|
+
// amendment 65 (mnemom-test#1331): the two single-use exchange refusals, appended
|
|
2577
|
+
"oidc_token_replayed",
|
|
2578
|
+
"oidc_run_already_exchanged"
|
|
2505
2579
|
];
|
|
2506
2580
|
var RUNNER_OPEN_MODE_TOLERATED = [
|
|
2507
2581
|
"bundle_unavailable",
|
|
@@ -2747,7 +2821,9 @@ var DURABLE_EVENT_KINDS = [
|
|
|
2747
2821
|
"session.waiting",
|
|
2748
2822
|
"session.wait_cleared",
|
|
2749
2823
|
"executor.turn_continued",
|
|
2750
|
-
"inbox.acked"
|
|
2824
|
+
"inbox.acked",
|
|
2825
|
+
// S1 amendment 64: dispatch parked a seal (api-written; session.waiting stays executor-only)
|
|
2826
|
+
"session.dispatch_parked"
|
|
2751
2827
|
];
|
|
2752
2828
|
function isDurableEventKind(v) {
|
|
2753
2829
|
return typeof v === "string" && DURABLE_EVENT_KINDS.includes(v);
|
|
@@ -2756,7 +2832,8 @@ var AMENDMENT_EVENT_GROUPS = Object.freeze({
|
|
|
2756
2832
|
"session.ready": "lifecycle",
|
|
2757
2833
|
"session.waiting": "lifecycle",
|
|
2758
2834
|
"session.wait_cleared": "lifecycle",
|
|
2759
|
-
"executor.turn_continued": "lease"
|
|
2835
|
+
"executor.turn_continued": "lease",
|
|
2836
|
+
"session.dispatch_parked": "lifecycle"
|
|
2760
2837
|
});
|
|
2761
2838
|
function eventGroupOf(kind) {
|
|
2762
2839
|
if (Object.prototype.hasOwnProperty.call(AMENDMENT_EVENT_GROUPS, kind))
|
|
@@ -3006,10 +3083,16 @@ var KIND_REFS = {
|
|
|
3006
3083
|
[
|
|
3007
3084
|
{ field: "wait_reason", equals: "ci", require: ["head_sha"], forbid: ["approval_id"] },
|
|
3008
3085
|
{ field: "wait_reason", equals: "question", require: ["approval_id"], forbid: ["head_sha"] },
|
|
3009
|
-
{ field: "wait_reason", equals: "budget", require: ["approval_id"], forbid: ["head_sha"] }
|
|
3086
|
+
{ field: "wait_reason", equals: "budget", require: ["approval_id"], forbid: ["head_sha"] },
|
|
3087
|
+
// amendment 64: a dispatch park carries no commitment
|
|
3088
|
+
{ field: "wait_reason", equals: "awaiting_issue_run", forbid: ["head_sha", "approval_id"] },
|
|
3089
|
+
{ field: "wait_reason", equals: "repo_arm_unreadable", forbid: ["head_sha", "approval_id"] }
|
|
3010
3090
|
]
|
|
3011
3091
|
),
|
|
3012
3092
|
"session.wait_cleared": obj({ wait_reason: ENUM(PARKED_ONLY_WAIT_REASONS) }),
|
|
3093
|
+
// S1 amendment 64: the api's dispatch park. One writer per kind: the executor's park stays
|
|
3094
|
+
// session.waiting; adopt and flip-to-runner journal session.wait_cleared + session.ready.
|
|
3095
|
+
"session.dispatch_parked": obj({ wait_reason: ENUM(DISPATCH_PARK_WAIT_REASONS) }),
|
|
3013
3096
|
// ---- lead ruling 2026-10-28: the spawn that sent the continue; a separate fact, so
|
|
3014
3097
|
// executor.spawned's refs stay exactly {spawn_id} ----
|
|
3015
3098
|
"executor.turn_continued": obj({ spawn_id: UUID }),
|
|
@@ -4341,12 +4424,14 @@ async function approvalSubjectHash(subject) {
|
|
|
4341
4424
|
return sha256Hex(canonicalJson(subject));
|
|
4342
4425
|
}
|
|
4343
4426
|
var AGENT_SESSIONS_READY_CHECK = "state <> 'ready' OR (durable_mode = 'locked' AND state_reason IS NULL AND home_executor_id IS NULL AND lease_executor_id IS NULL AND lease_expires_at IS NULL AND spawn_id IS NULL AND hello_at IS NULL)";
|
|
4344
|
-
var AGENT_SESSIONS_WAIT_PARKED_CHECK = "CASE WHEN wait_reason IN ('ci','question','budget') THEN state = 'parked' AND wait_ref IS NOT NULL ELSE wait_ref IS NULL END";
|
|
4427
|
+
var AGENT_SESSIONS_WAIT_PARKED_CHECK = "CASE WHEN wait_reason IN ('ci','question','budget') THEN state = 'parked' AND wait_ref IS NOT NULL WHEN wait_reason IN ('awaiting_issue_run','repo_arm_unreadable') THEN state = 'parked' AND wait_ref IS NULL ELSE wait_ref IS NULL END";
|
|
4345
4428
|
var AGENT_EXECUTORS_SCOPE_CHECK = "scope IN ('user','org')";
|
|
4346
4429
|
function readyRowOk(row) {
|
|
4347
4430
|
return row.state !== "ready" || row.durable_mode === "locked" && row.state_reason === null && row.home_executor_id === null && row.lease_executor_id === null && row.lease_expires_at === null && row.spawn_id === null && row.hello_at === null;
|
|
4348
4431
|
}
|
|
4349
4432
|
function waitParkedRowOk(row) {
|
|
4433
|
+
if (row.wait_reason !== null && DISPATCH_PARK_WAIT_REASONS.includes(row.wait_reason))
|
|
4434
|
+
return row.state === "parked" && row.wait_ref === null;
|
|
4350
4435
|
return row.wait_reason !== null && PARKED_ONLY_WAIT_REASONS.includes(row.wait_reason) ? row.state === "parked" && row.wait_ref !== null : row.wait_ref === null;
|
|
4351
4436
|
}
|
|
4352
4437
|
|
|
@@ -4852,6 +4937,16 @@ function executorStateOk(v) {
|
|
|
4852
4937
|
}
|
|
4853
4938
|
|
|
4854
4939
|
// ../shared/durable-contract/src/routes.ts
|
|
4940
|
+
var ADOPT_BODY_KEYS = ["source_ref", "nonce"];
|
|
4941
|
+
var ADOPT_SOURCE_REF_MAX = 500;
|
|
4942
|
+
function adoptBodyOk(v) {
|
|
4943
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
4944
|
+
const b = v;
|
|
4945
|
+
if (Object.keys(b).length !== 2 || typeof b.source_ref !== "string") return false;
|
|
4946
|
+
if (typeof b.nonce !== "string" || b.nonce.length === 0) return false;
|
|
4947
|
+
const r = b.source_ref;
|
|
4948
|
+
return r !== "" && r === r.trim() && r.length <= ADOPT_SOURCE_REF_MAX;
|
|
4949
|
+
}
|
|
4855
4950
|
var fixed = (method, auth, path) => Object.freeze({ method, auth, path });
|
|
4856
4951
|
var scoped = (method, auth, pre, post) => Object.freeze({ method, auth, pre, post });
|
|
4857
4952
|
var EXECUTORS = "/v1/executors";
|
|
@@ -4882,8 +4977,21 @@ var ROUTES = Object.freeze({
|
|
|
4882
4977
|
// ---- Doors amendment (ruling 34.03) ----
|
|
4883
4978
|
/** The org-scope executor's claimable pool sessions, oldest first; `?limit=` (READY_SESSIONS_LIMIT_MIN..MAX) is not part of the match. */
|
|
4884
4979
|
exec_ready_list: fixed("GET", "executor_key", "/v1/executor/ready"),
|
|
4885
|
-
/**
|
|
4980
|
+
/**
|
|
4981
|
+
* Body {oidc_token, adopt_ticket?} (doors.ts oidcExchangeBodyOk, Amendment 66). adopt_ticket comes
|
|
4982
|
+
* only from a ticketed wake-up; it is used up before any key is minted and binds the key to one seal.
|
|
4983
|
+
* Amendment 65: single-use per token jti and per run attempt (token_replayed, run_already_exchanged).
|
|
4984
|
+
*/
|
|
4886
4985
|
exec_oidc_exchange: fixed("POST", "github_oidc", "/v1/executor/oidc/exchange"),
|
|
4986
|
+
// ---- S1 amendment 64 (mnemom-test#1336) ----
|
|
4987
|
+
/**
|
|
4988
|
+
* Body {source_ref, nonce} (adoptBodyOk). The OIDC run's key unparks the parked dispatch seal whose
|
|
4989
|
+
* source_ref is this run's own issue, in its own org and repo, and claims it in one transaction,
|
|
4990
|
+
* and only the seal its adopt ticket was minted for (Amendment 66; a key with no ticket adopts none),
|
|
4991
|
+
* fenced on the nonce (exec_claim's rule);
|
|
4992
|
+
* answers the exec_claim answer, or adopt_refused / seal_repo_mismatch, changing nothing.
|
|
4993
|
+
*/
|
|
4994
|
+
exec_adopt: fixed("POST", "executor_key", "/v1/executor/adopt"),
|
|
4887
4995
|
// ---- inbox, executor side (S1 amendment 60) ----
|
|
4888
4996
|
/** Content-free summary {admitted, delivered, oldest_admitted_at} (inboxSummaryResponseOk); marks nothing. */
|
|
4889
4997
|
exec_inbox: scoped("GET", "executor_key", EXEC_SESSION_PRE, "/inbox"),
|
|
@@ -5807,8 +5915,24 @@ var FREEZE_RECORD = Object.freeze({
|
|
|
5807
5915
|
DEFAULT_LEASE_CAP_ENV,
|
|
5808
5916
|
DISPATCH_SESSION_CID_PREFIX,
|
|
5809
5917
|
DISPATCH_SESSION_NAME_PREFIX,
|
|
5918
|
+
// amendment 66
|
|
5919
|
+
ADOPT_TICKET_INPUT,
|
|
5920
|
+
WAKEUP_SESSION_INPUT,
|
|
5921
|
+
ADOPT_TICKET_PATTERN: ADOPT_TICKET_RE.source,
|
|
5922
|
+
ADOPT_TICKET_TTL_S,
|
|
5923
|
+
OIDC_TOKEN_MAX,
|
|
5924
|
+
OIDC_WORKFLOW_ENV,
|
|
5925
|
+
OIDC_WORKFLOW_FILE_PATTERN: OIDC_WORKFLOW_FILE_RE.source,
|
|
5926
|
+
OIDC_WORKFLOW_SET_ENV,
|
|
5927
|
+
OIDC_WORKFLOW_SET_MAX,
|
|
5810
5928
|
READY_SESSIONS_LIMIT_MIN,
|
|
5811
5929
|
READY_SESSIONS_LIMIT_MAX,
|
|
5930
|
+
// amendment 64
|
|
5931
|
+
ADOPT_SOURCE_REF_MAX,
|
|
5932
|
+
// amendment 65
|
|
5933
|
+
OIDC_JTI_MAX,
|
|
5934
|
+
OIDC_RUN_NUMBER_PATTERN: OIDC_RUN_NUMBER_RE.source,
|
|
5935
|
+
OIDC_EXCHANGE_RETENTION_DAYS,
|
|
5812
5936
|
READY_USER_TEXT,
|
|
5813
5937
|
RUNNER_FAILED_PHASE_PATTERN: RUNNER_FAILED_PHASE_RE.source,
|
|
5814
5938
|
AGENT_SESSIONS_READY_CHECK,
|
|
@@ -5921,11 +6045,17 @@ var FREEZE_STRUCTURED = Object.freeze({
|
|
|
5921
6045
|
READY_CAUSES,
|
|
5922
6046
|
WAIT_REASONS,
|
|
5923
6047
|
PARKED_ONLY_WAIT_REASONS,
|
|
6048
|
+
// amendment 64
|
|
6049
|
+
DISPATCH_PARK_WAIT_REASONS,
|
|
6050
|
+
ADOPT_REFUSED_CAUSES,
|
|
6051
|
+
ADOPT_BODY_KEYS,
|
|
5924
6052
|
WAIT_REF_KEYS,
|
|
5925
6053
|
CLEAR_WAIT_OUTCOMES,
|
|
5926
6054
|
EXECUTOR_SCOPES,
|
|
5927
6055
|
ORG_SCOPE_EXECUTOR_KINDS,
|
|
5928
6056
|
OIDC_EXCHANGE_REFUSALS,
|
|
6057
|
+
OIDC_EXCHANGE_BODY_KEYS,
|
|
6058
|
+
OIDC_EXCHANGE_RUN_CLAIMS,
|
|
5929
6059
|
ORG_POLICY_LIMIT_KEYS,
|
|
5930
6060
|
POOL_CLAIM_FIELDS,
|
|
5931
6061
|
CREATE_READY_SESSION_REFUSALS,
|
|
@@ -6234,6 +6364,12 @@ export {
|
|
|
6234
6364
|
ADMISSION_STEP_CODE,
|
|
6235
6365
|
ADMIT_SWEEP_VALUES,
|
|
6236
6366
|
ADMIT_SWEEP_VECTORS_PATH,
|
|
6367
|
+
ADOPT_BODY_KEYS,
|
|
6368
|
+
ADOPT_REFUSED_CAUSES,
|
|
6369
|
+
ADOPT_SOURCE_REF_MAX,
|
|
6370
|
+
ADOPT_TICKET_INPUT,
|
|
6371
|
+
ADOPT_TICKET_RE,
|
|
6372
|
+
ADOPT_TICKET_TTL_S,
|
|
6237
6373
|
ADOPT_WITH_YOU_TEXT,
|
|
6238
6374
|
AGENT_CONTAINED_STATUSES,
|
|
6239
6375
|
AGENT_EXECUTORS_SCOPE_CHECK,
|
|
@@ -6315,6 +6451,7 @@ export {
|
|
|
6315
6451
|
DEVICE_STEP_VERBS,
|
|
6316
6452
|
DEVICE_VERIFY_AAL_DEFAULT,
|
|
6317
6453
|
DEVICE_VERIFY_AAL_VALUES,
|
|
6454
|
+
DISPATCH_PARK_WAIT_REASONS,
|
|
6318
6455
|
DISPATCH_SESSION_CID_PREFIX,
|
|
6319
6456
|
DISPATCH_SESSION_NAME_PREFIX,
|
|
6320
6457
|
DONE_CLAUSE,
|
|
@@ -6487,7 +6624,17 @@ export {
|
|
|
6487
6624
|
NON_TTY_LOCKED_TEMPLATE,
|
|
6488
6625
|
NO_M1_EMITTER_KINDS,
|
|
6489
6626
|
OIDC_EXCHANGE_AUDIENCE,
|
|
6627
|
+
OIDC_EXCHANGE_BODY_KEYS,
|
|
6490
6628
|
OIDC_EXCHANGE_REFUSALS,
|
|
6629
|
+
OIDC_EXCHANGE_RETENTION_DAYS,
|
|
6630
|
+
OIDC_EXCHANGE_RUN_CLAIMS,
|
|
6631
|
+
OIDC_JTI_MAX,
|
|
6632
|
+
OIDC_RUN_NUMBER_RE,
|
|
6633
|
+
OIDC_TOKEN_MAX,
|
|
6634
|
+
OIDC_WORKFLOW_ENV,
|
|
6635
|
+
OIDC_WORKFLOW_FILE_RE,
|
|
6636
|
+
OIDC_WORKFLOW_SET_ENV,
|
|
6637
|
+
OIDC_WORKFLOW_SET_MAX,
|
|
6491
6638
|
OLD_ROUTE_BRANCH,
|
|
6492
6639
|
OLD_ROUTE_REFRESH,
|
|
6493
6640
|
ORG_CAP_LOCK_PREFIX,
|
|
@@ -6665,11 +6812,14 @@ export {
|
|
|
6665
6812
|
UUID_RE,
|
|
6666
6813
|
WAIT_REASONS,
|
|
6667
6814
|
WAIT_REF_KEYS,
|
|
6815
|
+
WAKEUP_SESSION_INPUT,
|
|
6668
6816
|
admissionStatusOf,
|
|
6669
6817
|
admissionTruthTable,
|
|
6670
6818
|
admit,
|
|
6671
6819
|
admitSweepDigest,
|
|
6672
6820
|
admitSweepText,
|
|
6821
|
+
adoptBodyOk,
|
|
6822
|
+
adoptTicketOk,
|
|
6673
6823
|
amendDecision,
|
|
6674
6824
|
answerFromChoice,
|
|
6675
6825
|
answersOk,
|
|
@@ -6797,6 +6947,8 @@ export {
|
|
|
6797
6947
|
isValidSessionName,
|
|
6798
6948
|
isValidStateReason,
|
|
6799
6949
|
isWellFormedLeaseKey,
|
|
6950
|
+
jobWorkflowRefInSet,
|
|
6951
|
+
jobWorkflowRefOk,
|
|
6800
6952
|
lagBucket,
|
|
6801
6953
|
lintDurableOnly,
|
|
6802
6954
|
lintFixCatalogue,
|
|
@@ -6808,6 +6960,10 @@ export {
|
|
|
6808
6960
|
normalizeCellId,
|
|
6809
6961
|
normalizeQuestions,
|
|
6810
6962
|
normalizeSessionName,
|
|
6963
|
+
oidcExchangeBodyOk,
|
|
6964
|
+
oidcPinnedWorkflow,
|
|
6965
|
+
oidcRunClaimsOk,
|
|
6966
|
+
oidcWorkflowSet,
|
|
6811
6967
|
openContract,
|
|
6812
6968
|
ownerSessionViewOk,
|
|
6813
6969
|
ownerVerbDecision,
|
|
@@ -15,6 +15,14 @@ export type ClaimUnavailableCause = (typeof CLAIM_UNAVAILABLE_CAUSES)[number];
|
|
|
15
15
|
*/
|
|
16
16
|
export declare const SEAL_REPO_MISMATCH_CAUSES: readonly ["no_repo_claim", "no_seal_repo", "repo_mismatch"];
|
|
17
17
|
export type SealRepoMismatchCause = (typeof SEAL_REPO_MISMATCH_CAUSES)[number];
|
|
18
|
+
/**
|
|
19
|
+
* adopt_refused details.cause (S1 amendment 64, mnemom-test#1336; exec_adopt): no parked dispatch
|
|
20
|
+
* seal names this source_ref in the caller's own org and repo (never says whether one exists
|
|
21
|
+
* elsewhere), or the seal's session is not parked and the caller is not the OIDC run that already
|
|
22
|
+
* holds its lease. A repo or binding mismatch is seal_repo_mismatch, not this code.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ADOPT_REFUSED_CAUSES: readonly ["no_parked_seal", "not_parked"];
|
|
25
|
+
export type AdoptRefusedCause = (typeof ADOPT_REFUSED_CAUSES)[number];
|
|
18
26
|
export declare const UNSUPPORTED_FEATURES: readonly ["tool_classes", "launch_spec_change", "above_limit_raise", "remote_control"];
|
|
19
27
|
export type UnsupportedFeature = (typeof UNSUPPORTED_FEATURES)[number];
|
|
20
28
|
export declare const CWD_KINDS: readonly ["subdirectory", "not_git", "symlink_transcript"];
|
|
@@ -273,6 +281,11 @@ export declare const DURABLE_CODES: {
|
|
|
273
281
|
readonly surfaces: readonly ["api"];
|
|
274
282
|
readonly fields: readonly ["cause"];
|
|
275
283
|
};
|
|
284
|
+
readonly adopt_refused: {
|
|
285
|
+
readonly status: 409;
|
|
286
|
+
readonly surfaces: readonly ["api"];
|
|
287
|
+
readonly fields: readonly ["cause"];
|
|
288
|
+
};
|
|
276
289
|
/** Lost CAS race on (session_id, seq). */
|
|
277
290
|
readonly durable_append_conflict: {
|
|
278
291
|
readonly status: 409;
|
|
@@ -24,6 +24,13 @@ export const CLAIM_UNAVAILABLE_CAUSES = [
|
|
|
24
24
|
* another repo than the executor's (owner/name, case-insensitive).
|
|
25
25
|
*/
|
|
26
26
|
export const SEAL_REPO_MISMATCH_CAUSES = ["no_repo_claim", "no_seal_repo", "repo_mismatch"];
|
|
27
|
+
/**
|
|
28
|
+
* adopt_refused details.cause (S1 amendment 64, mnemom-test#1336; exec_adopt): no parked dispatch
|
|
29
|
+
* seal names this source_ref in the caller's own org and repo (never says whether one exists
|
|
30
|
+
* elsewhere), or the seal's session is not parked and the caller is not the OIDC run that already
|
|
31
|
+
* holds its lease. A repo or binding mismatch is seal_repo_mismatch, not this code.
|
|
32
|
+
*/
|
|
33
|
+
export const ADOPT_REFUSED_CAUSES = ["no_parked_seal", "not_parked"];
|
|
27
34
|
export const UNSUPPORTED_FEATURES = [
|
|
28
35
|
"tool_classes",
|
|
29
36
|
"launch_spec_change",
|
|
@@ -145,6 +152,9 @@ export const DURABLE_CODES = {
|
|
|
145
152
|
// durable_claim_ineligible reason: the session is claimable, only not by this executor, and a
|
|
146
153
|
// runner never skips past it to another session. cause is a SEAL_REPO_MISMATCH_CAUSES value.
|
|
147
154
|
seal_repo_mismatch: { status: 403, surfaces: ["api"], fields: ["cause"] },
|
|
155
|
+
// S1 amendment 64 (mnemom-test#1336): exec_adopt found nothing it may unpark for this run. Nothing
|
|
156
|
+
// is written. cause is an ADOPT_REFUSED_CAUSES value.
|
|
157
|
+
adopt_refused: { status: 409, surfaces: ["api"], fields: ["cause"] },
|
|
148
158
|
// ---- api journal (C10-R0 (i), (j), (k)) ----
|
|
149
159
|
/** Lost CAS race on (session_id, seq). */
|
|
150
160
|
durable_append_conflict: { status: 409, surfaces: ["api"], fields: ["tip_seq"] },
|