@mnemom/mnemom 0.17.33 → 0.17.34-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/base-url-proxy.mjs +18 -4
- package/dist/commands/agent-config.js +5 -1
- package/dist/commands/agent-doctor.d.ts +9 -0
- package/dist/commands/agent-doctor.js +4 -0
- package/dist/commands/agent-session.d.ts +1 -2
- package/dist/commands/agent-session.js +1 -2
- package/dist/commands/agent-setup.d.ts +6 -0
- package/dist/commands/agent-setup.js +12 -1
- package/dist/commands/agent-share-render.d.ts +1 -1
- package/dist/commands/agent-share-render.js +1 -1
- package/dist/commands/agent.d.ts +26 -0
- package/dist/commands/agent.js +228 -53
- package/dist/commands/durable-doctor.d.ts +50 -0
- package/dist/commands/durable-doctor.js +186 -0
- package/dist/commands/durable-lock.d.ts +254 -0
- package/dist/commands/durable-lock.js +595 -0
- package/dist/commands/durable-sessions.d.ts +87 -0
- package/dist/commands/durable-sessions.js +303 -0
- package/dist/commands/durable-verbs.d.ts +116 -0
- package/dist/commands/durable-verbs.js +393 -0
- package/dist/commands/protection.js +1 -1
- package/dist/commands/scan.d.ts +97 -0
- package/dist/commands/scan.js +238 -0
- package/dist/durable/flock.d.ts +26 -0
- package/dist/durable/flock.js +80 -0
- package/dist/durable/launch-spec.d.ts +7 -1
- package/dist/durable/launch-spec.js +10 -3
- package/dist/durable/seat-proxy-entry.d.ts +11 -0
- package/dist/durable/seat-proxy-entry.js +25 -0
- package/dist/durable/seat-proxy.d.ts +107 -0
- package/dist/durable/seat-proxy.js +599 -0
- package/dist/durable/seat-socket.d.ts +46 -0
- package/dist/durable/seat-socket.js +179 -0
- package/dist/durable/seat-spec-validator.d.ts +28 -0
- package/dist/durable/seat-spec-validator.js +59 -0
- package/dist/durable/test-mode.mjs +81 -0
- package/dist/durable/turn-chain.d.ts +55 -0
- package/dist/durable/turn-chain.js +178 -0
- package/dist/host/auto-continue.d.ts +67 -0
- package/dist/host/auto-continue.js +118 -0
- package/dist/host/bootid.d.ts +13 -0
- package/dist/host/bootid.js +41 -0
- package/dist/host/client.d.ts +123 -0
- package/dist/host/client.js +171 -0
- package/dist/host/commands.d.ts +2 -0
- package/dist/host/commands.js +122 -0
- package/dist/host/control.d.ts +33 -0
- package/dist/host/control.js +144 -0
- package/dist/host/daemon.d.ts +217 -0
- package/dist/host/daemon.js +606 -0
- package/dist/host/gate.d.ts +46 -0
- package/dist/host/gate.js +82 -0
- package/dist/host/grant.d.ts +24 -0
- package/dist/host/grant.js +24 -0
- package/dist/host/instance.d.ts +35 -0
- package/dist/host/instance.js +62 -0
- package/dist/host/integrity.d.ts +35 -0
- package/dist/host/integrity.js +115 -0
- package/dist/host/launchd.d.ts +16 -0
- package/dist/host/launchd.js +45 -0
- package/dist/host/lock.d.ts +20 -0
- package/dist/host/lock.js +63 -0
- package/dist/host/owner.d.ts +55 -0
- package/dist/host/owner.js +121 -0
- package/dist/host/plist.d.ts +16 -0
- package/dist/host/plist.js +85 -0
- package/dist/host/procs.d.ts +27 -0
- package/dist/host/procs.js +105 -0
- package/dist/host/run.d.ts +66 -0
- package/dist/host/run.js +314 -0
- package/dist/host/runtime.d.ts +8 -0
- package/dist/host/runtime.js +22 -0
- package/dist/host/s1-names.d.ts +22 -0
- package/dist/host/s1-names.js +21 -0
- package/dist/host/seat-credential.d.ts +27 -0
- package/dist/host/seat-credential.js +41 -0
- package/dist/host/seat-launch-main.d.ts +1 -0
- package/dist/host/seat-launch-main.js +59 -0
- package/dist/host/seat-launch.d.ts +116 -0
- package/dist/host/seat-launch.js +302 -0
- package/dist/host/seat.d.ts +48 -0
- package/dist/host/seat.js +149 -0
- package/dist/host/state.d.ts +33 -0
- package/dist/host/state.js +117 -0
- package/dist/host/status.d.ts +101 -0
- package/dist/host/status.js +307 -0
- package/dist/host/tmux.d.ts +56 -0
- package/dist/host/tmux.js +182 -0
- package/dist/host/transcript.d.ts +30 -0
- package/dist/host/transcript.js +130 -0
- package/dist/host/verbs.d.ts +50 -0
- package/dist/host/verbs.js +271 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +232 -35
- package/dist/lib/agent.d.ts +8 -26
- package/dist/lib/agent.js +11 -26
- package/dist/lib/api.d.ts +13 -0
- package/dist/lib/api.js +8 -0
- package/dist/lib/claude-plugin.d.ts +11 -2
- package/dist/lib/claude-plugin.js +10 -1
- package/dist/lib/durable/api.d.ts +136 -0
- package/dist/lib/durable/api.js +220 -0
- package/dist/lib/durable/codes.d.ts +8 -0
- package/dist/lib/durable/codes.js +2 -0
- package/dist/lib/durable/first-turn.d.ts +50 -0
- package/dist/lib/durable/first-turn.js +102 -0
- package/dist/lib/durable/gate.d.ts +48 -0
- package/dist/lib/durable/gate.js +122 -0
- package/dist/lib/durable/handover.d.ts +101 -0
- package/dist/lib/durable/handover.js +175 -0
- package/dist/lib/durable/launch.d.ts +182 -0
- package/dist/lib/durable/launch.js +443 -0
- package/dist/lib/durable/launching.d.ts +15 -0
- package/dist/lib/durable/launching.js +70 -0
- package/dist/lib/durable/live.d.ts +194 -0
- package/dist/lib/durable/live.js +635 -0
- package/dist/lib/durable/refusal.d.ts +57 -0
- package/dist/lib/durable/refusal.js +78 -0
- package/dist/lib/durable/view.d.ts +83 -0
- package/dist/lib/durable/view.js +244 -0
- package/dist/lib/experimental.d.ts +0 -9
- package/dist/lib/experimental.js +18 -17
- package/dist/lib/launcher-config.d.ts +7 -0
- package/dist/lib/launcher-config.js +21 -0
- package/dist/lib/scan/caps.d.ts +35 -0
- package/dist/lib/scan/caps.js +67 -0
- package/dist/lib/scan/credential.d.ts +37 -0
- package/dist/lib/scan/credential.js +104 -0
- package/dist/lib/scan/failure.d.ts +10 -0
- package/dist/lib/scan/failure.js +43 -0
- package/dist/lib/scan/pr-source.d.ts +57 -0
- package/dist/lib/scan/pr-source.js +130 -0
- package/dist/lib/scan/record.d.ts +49 -0
- package/dist/lib/scan/record.js +85 -0
- package/dist/lib/scan/report-email.d.ts +92 -0
- package/dist/lib/scan/report-email.js +144 -0
- package/dist/lib/scan/report.d.ts +13 -0
- package/dist/lib/scan/report.js +30 -0
- package/dist/lib/scan/scan.d.ts +64 -0
- package/dist/lib/scan/scan.js +182 -0
- package/dist/lib/scan/share.d.ts +38 -0
- package/dist/lib/scan/share.js +47 -0
- package/dist/lib/scan/spend/ai-tool-detect.d.ts +6 -0
- package/dist/lib/scan/spend/ai-tool-detect.js +18 -0
- package/dist/lib/scan/spend/anthropic-usage.d.ts +57 -0
- package/dist/lib/scan/spend/anthropic-usage.js +244 -0
- package/dist/lib/scan/spend/cost-corpus.v1.d.ts +56 -0
- package/dist/lib/scan/spend/cost-corpus.v1.js +64 -0
- package/dist/lib/scan/spend/prices.d.ts +33 -0
- package/dist/lib/scan/spend/prices.js +57 -0
- package/dist/lib/scan/spend/spend-estimate.d.ts +30 -0
- package/dist/lib/scan/spend/spend-estimate.js +70 -0
- package/dist/lib/scan/spend/spend-tiers.d.ts +25 -0
- package/dist/lib/scan/spend/spend-tiers.js +42 -0
- package/dist/lib/scan/spend/token-rate.d.ts +30 -0
- package/dist/lib/scan/spend/token-rate.js +54 -0
- package/dist/lib/session-key.d.ts +41 -0
- package/dist/lib/session-key.js +124 -0
- package/dist/lib/subscription-login.d.ts +15 -0
- package/dist/lib/subscription-login.js +28 -1
- package/dist/rc-key-401.mjs +75 -0
- package/dist/rc-proxy.mjs +221 -25
- package/dist/vendor/durable-contract/index.js +240 -18
- package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
- package/dist/vendor/shared/durable-contract/admission.js +533 -0
- package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
- package/dist/vendor/shared/durable-contract/arm.js +133 -0
- package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/canonical.js +98 -0
- package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
- package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
- package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
- package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
- package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
- package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
- package/dist/vendor/shared/durable-contract/codes.js +475 -0
- package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
- package/dist/vendor/shared/durable-contract/constants.js +179 -0
- package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/doors.js +249 -0
- package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
- package/dist/vendor/shared/durable-contract/envelope.js +317 -0
- package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
- package/dist/vendor/shared/durable-contract/events.js +630 -0
- package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
- package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
- package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
- package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
- package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
- package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
- package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
- package/dist/vendor/shared/durable-contract/index.js +37 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
- package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
- package/dist/vendor/shared/durable-contract/keys.js +66 -0
- package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
- package/dist/vendor/shared/durable-contract/lock.js +151 -0
- package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
- package/dist/vendor/shared/durable-contract/names.js +78 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
- package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
- package/dist/vendor/shared/durable-contract/paths.js +35 -0
- package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
- package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
- package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
- package/dist/vendor/shared/durable-contract/routes.js +315 -0
- package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
- package/dist/vendor/shared/durable-contract/schema.js +441 -0
- package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
- package/dist/vendor/shared/durable-contract/seal.js +99 -0
- package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
- package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
- package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
- package/dist/vendor/shared/durable-contract/session-id.js +58 -0
- package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
- package/dist/vendor/shared/durable-contract/spec.js +286 -0
- package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
- package/dist/vendor/shared/durable-contract/states.js +218 -0
- package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
- package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
- package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
- package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
- package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
- package/dist/vendor/shared/durable-contract/turn.js +81 -0
- package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
- package/dist/vendor/shared/durable-contract/vectors.js +208 -0
- package/package.json +4 -3
- package/plugins/integrity-manifest.json +35 -0
- package/plugins/mnemom/hooks/hooks.json +15 -1
- package/plugins/mnemom/hooks/register.tsx +60 -2
- package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
- package/dist/commands/agent-implicit-notice.d.ts +0 -31
- package/dist/commands/agent-implicit-notice.js +0 -73
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
// GENERATED from shared/durable-contract/src/events.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
|
|
2
|
+
/**
|
|
3
|
+
* The journal: the closed event vocabulary (design §3.7, BACKBONE "Event kinds list", C10-R1..R25),
|
|
4
|
+
* writer classes, refs schemas, the server-generated detail, idempotency keys and the hash
|
|
5
|
+
* preimage (C10-R0 (a)-(m)).
|
|
6
|
+
*
|
|
7
|
+
* C10-R0 decisions frozen here:
|
|
8
|
+
* (a) preimage fields: EVENT_PREIMAGE_FIELDS; hash = sha256(canonicalJson(preimage)).
|
|
9
|
+
* (b) genesis prev_hash: GENESIS_PREV_HASH (64 zeros), never null.
|
|
10
|
+
* (c) ts: stamped by the API process at append (Date, millisecond precision), stored timestamptz,
|
|
11
|
+
* hashed as canonicalEventTs(ts): UTC, exactly 6 fraction digits, "Z" (survives PostgREST's
|
|
12
|
+
* "+00:00" and psql's "+00" read-back forms).
|
|
13
|
+
* (d) principal_ref: a stored column, HMAC-SHA256(hmac_salt, principal_uid) hex, null when the
|
|
14
|
+
* writer has no principal (gateway, sweep, trigger).
|
|
15
|
+
* (e) writer classes: EVENT_WRITER; executor list exactly [executor.spawned], plus session.waiting
|
|
16
|
+
* from the Doors amendment (ruling 34.06) and executor.turn_continued (lead ruling 2026-10-28).
|
|
17
|
+
* (f) executor.enrolled is journaled into no session in M1 (the agent_executors row is the record).
|
|
18
|
+
* (h) an epoch-bump event is stamped with the NEW epoch.
|
|
19
|
+
* (i)(j) codes.ts: durable_append_conflict, durable_lease_fenced, durable_idempotency_conflict.
|
|
20
|
+
* (k) refs_schema is enforced inside durable_append_event (so a direct service_role RPC is refused).
|
|
21
|
+
* (l) the gateway's internal route is GATEWAY_EVENTS_ROUTE on the API.
|
|
22
|
+
* (m) DSR: phase user_erasure, treatment pseudonymize (nulls principal_uid, detail, refs).
|
|
23
|
+
*/
|
|
24
|
+
import { canonicalJson, hmacSha256Hex, sha256Hex, HEX64_RE } from "./canonical.js";
|
|
25
|
+
import { DETACHED_REASONS, PAUSED_REASONS, SUSPENDED_REASONS, FAILED_REASONS, PARKED_ONLY_WAIT_REASONS, } from "./states.js";
|
|
26
|
+
import { ATTESTATION_CHECKS_M1, CWD_CHECK_CAUSES } from "./codes.js";
|
|
27
|
+
import { EVENT_DETAIL_MAX_CHARS } from "./constants.js";
|
|
28
|
+
export const EVENT_GROUPS = [
|
|
29
|
+
"lifecycle",
|
|
30
|
+
"charter",
|
|
31
|
+
"lease",
|
|
32
|
+
"input",
|
|
33
|
+
"human",
|
|
34
|
+
"effects",
|
|
35
|
+
"governance",
|
|
36
|
+
"context",
|
|
37
|
+
];
|
|
38
|
+
/** The §3.7 table, all 88 kinds, by group. */
|
|
39
|
+
export const DESIGN_EVENT_KINDS = {
|
|
40
|
+
lifecycle: [
|
|
41
|
+
"session.registered",
|
|
42
|
+
"session.locked",
|
|
43
|
+
"session.unlocked",
|
|
44
|
+
"session.resumed",
|
|
45
|
+
"session.detached",
|
|
46
|
+
"session.parked",
|
|
47
|
+
"session.suspended",
|
|
48
|
+
"session.paused",
|
|
49
|
+
"session.unpaused",
|
|
50
|
+
"session.moved",
|
|
51
|
+
"session.completed",
|
|
52
|
+
"session.failed",
|
|
53
|
+
"session.killed",
|
|
54
|
+
"session.expired",
|
|
55
|
+
"session.adopted",
|
|
56
|
+
"seat.hello",
|
|
57
|
+
],
|
|
58
|
+
charter: [
|
|
59
|
+
"charter.sealed",
|
|
60
|
+
"charter.amended",
|
|
61
|
+
"charter.goal_sealed",
|
|
62
|
+
"charter.card_drift",
|
|
63
|
+
"profile.amended",
|
|
64
|
+
"executor.upgraded",
|
|
65
|
+
"attestation.passed",
|
|
66
|
+
"attestation.failed",
|
|
67
|
+
],
|
|
68
|
+
lease: [
|
|
69
|
+
"lease.acquired",
|
|
70
|
+
"lease.reclaimed",
|
|
71
|
+
"lease.released",
|
|
72
|
+
"lease.expired",
|
|
73
|
+
"lease.fenced",
|
|
74
|
+
"lease.zombie_call",
|
|
75
|
+
"lease.stale_admit",
|
|
76
|
+
"executor.enrolled",
|
|
77
|
+
"executor.revoked",
|
|
78
|
+
"executor.spawned",
|
|
79
|
+
"executor.exited",
|
|
80
|
+
"executor.contract_violation",
|
|
81
|
+
],
|
|
82
|
+
input: [
|
|
83
|
+
"inbox.admitted",
|
|
84
|
+
"inbox.rejected",
|
|
85
|
+
"inbox.coalesced",
|
|
86
|
+
"inbox.held_unsealed",
|
|
87
|
+
"inbox.queued_for_home",
|
|
88
|
+
"inbox.reverted",
|
|
89
|
+
"inbox.delivered",
|
|
90
|
+
"inbox.unmatched",
|
|
91
|
+
"inbox.acked",
|
|
92
|
+
"inbox.dead",
|
|
93
|
+
"timer.set",
|
|
94
|
+
"timer.fired",
|
|
95
|
+
"timer.cancelled",
|
|
96
|
+
"trigger.added",
|
|
97
|
+
"trigger.removed",
|
|
98
|
+
"trigger.fired",
|
|
99
|
+
"trigger.suppressed",
|
|
100
|
+
"trigger.over_cap",
|
|
101
|
+
"wake.undelivered",
|
|
102
|
+
],
|
|
103
|
+
human: [
|
|
104
|
+
"question.asked",
|
|
105
|
+
"question.answered",
|
|
106
|
+
"approval.requested",
|
|
107
|
+
"approval.resolved",
|
|
108
|
+
"approval.consumed",
|
|
109
|
+
"approval.expired",
|
|
110
|
+
"approval.superseded",
|
|
111
|
+
"approval.single_person_override",
|
|
112
|
+
],
|
|
113
|
+
effects: [
|
|
114
|
+
"intent.issued",
|
|
115
|
+
"intent.committed",
|
|
116
|
+
"intent.unknown",
|
|
117
|
+
"intent.resolved",
|
|
118
|
+
"intent.readmission_flagged",
|
|
119
|
+
"never.held",
|
|
120
|
+
],
|
|
121
|
+
governance: [
|
|
122
|
+
"chain.posture",
|
|
123
|
+
"guard.refused",
|
|
124
|
+
"guard.unavailable",
|
|
125
|
+
"budget.reached",
|
|
126
|
+
"grant.renewed",
|
|
127
|
+
"grant.revoked",
|
|
128
|
+
"verdict.violation",
|
|
129
|
+
"identity.mismatch",
|
|
130
|
+
"containment.pause",
|
|
131
|
+
"containment.kill",
|
|
132
|
+
"containment.auto_pause",
|
|
133
|
+
"governance.degraded_admit",
|
|
134
|
+
"governance.outage_mode_set",
|
|
135
|
+
"policy.host_unattended_changed",
|
|
136
|
+
],
|
|
137
|
+
context: [
|
|
138
|
+
"context.note",
|
|
139
|
+
"context.compacted",
|
|
140
|
+
"workspace.checkpointed",
|
|
141
|
+
"rearm.recorded",
|
|
142
|
+
"tip.signed",
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
/** The 8 kinds L01 leaves out of the M1 seed: unknown kinds on every write path in M1. */
|
|
146
|
+
export const M1_EXCLUDED_KINDS = [
|
|
147
|
+
"intent.issued",
|
|
148
|
+
"intent.committed",
|
|
149
|
+
"intent.unknown",
|
|
150
|
+
"intent.resolved",
|
|
151
|
+
"intent.readmission_flagged",
|
|
152
|
+
"context.note",
|
|
153
|
+
"context.compacted",
|
|
154
|
+
"inbox.acked",
|
|
155
|
+
];
|
|
156
|
+
/**
|
|
157
|
+
* Every M1 kind (80) with its group, in §3.7 order, then the Doors amendment's three (rulings
|
|
158
|
+
* 34.02, 34.06), appended so no existing index moves. Mirrors durable_event_kinds (parity test).
|
|
159
|
+
*/
|
|
160
|
+
export const DURABLE_EVENT_KINDS = [
|
|
161
|
+
"session.registered",
|
|
162
|
+
"session.locked",
|
|
163
|
+
"session.unlocked",
|
|
164
|
+
"session.resumed",
|
|
165
|
+
"session.detached",
|
|
166
|
+
"session.parked",
|
|
167
|
+
"session.suspended",
|
|
168
|
+
"session.paused",
|
|
169
|
+
"session.unpaused",
|
|
170
|
+
"session.moved",
|
|
171
|
+
"session.completed",
|
|
172
|
+
"session.failed",
|
|
173
|
+
"session.killed",
|
|
174
|
+
"session.expired",
|
|
175
|
+
"session.adopted",
|
|
176
|
+
"seat.hello",
|
|
177
|
+
"charter.sealed",
|
|
178
|
+
"charter.amended",
|
|
179
|
+
"charter.goal_sealed",
|
|
180
|
+
"charter.card_drift",
|
|
181
|
+
"profile.amended",
|
|
182
|
+
"executor.upgraded",
|
|
183
|
+
"attestation.passed",
|
|
184
|
+
"attestation.failed",
|
|
185
|
+
"lease.acquired",
|
|
186
|
+
"lease.reclaimed",
|
|
187
|
+
"lease.released",
|
|
188
|
+
"lease.expired",
|
|
189
|
+
"lease.fenced",
|
|
190
|
+
"lease.zombie_call",
|
|
191
|
+
"lease.stale_admit",
|
|
192
|
+
"executor.enrolled",
|
|
193
|
+
"executor.revoked",
|
|
194
|
+
"executor.spawned",
|
|
195
|
+
"executor.exited",
|
|
196
|
+
"executor.contract_violation",
|
|
197
|
+
"inbox.admitted",
|
|
198
|
+
"inbox.rejected",
|
|
199
|
+
"inbox.coalesced",
|
|
200
|
+
"inbox.held_unsealed",
|
|
201
|
+
"inbox.queued_for_home",
|
|
202
|
+
"inbox.reverted",
|
|
203
|
+
"inbox.delivered",
|
|
204
|
+
"inbox.unmatched",
|
|
205
|
+
"inbox.dead",
|
|
206
|
+
"timer.set",
|
|
207
|
+
"timer.fired",
|
|
208
|
+
"timer.cancelled",
|
|
209
|
+
"trigger.added",
|
|
210
|
+
"trigger.removed",
|
|
211
|
+
"trigger.fired",
|
|
212
|
+
"trigger.suppressed",
|
|
213
|
+
"trigger.over_cap",
|
|
214
|
+
"wake.undelivered",
|
|
215
|
+
"question.asked",
|
|
216
|
+
"question.answered",
|
|
217
|
+
"approval.requested",
|
|
218
|
+
"approval.resolved",
|
|
219
|
+
"approval.consumed",
|
|
220
|
+
"approval.expired",
|
|
221
|
+
"approval.superseded",
|
|
222
|
+
"approval.single_person_override",
|
|
223
|
+
"never.held",
|
|
224
|
+
"chain.posture",
|
|
225
|
+
"guard.refused",
|
|
226
|
+
"guard.unavailable",
|
|
227
|
+
"budget.reached",
|
|
228
|
+
"grant.renewed",
|
|
229
|
+
"grant.revoked",
|
|
230
|
+
"verdict.violation",
|
|
231
|
+
"identity.mismatch",
|
|
232
|
+
"containment.pause",
|
|
233
|
+
"containment.kill",
|
|
234
|
+
"containment.auto_pause",
|
|
235
|
+
"governance.degraded_admit",
|
|
236
|
+
"governance.outage_mode_set",
|
|
237
|
+
"policy.host_unattended_changed",
|
|
238
|
+
"workspace.checkpointed",
|
|
239
|
+
"rearm.recorded",
|
|
240
|
+
"tip.signed",
|
|
241
|
+
"session.ready",
|
|
242
|
+
"session.waiting",
|
|
243
|
+
"session.wait_cleared",
|
|
244
|
+
"executor.turn_continued",
|
|
245
|
+
];
|
|
246
|
+
export function isDurableEventKind(v) {
|
|
247
|
+
return typeof v === "string" && DURABLE_EVENT_KINDS.includes(v);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* The kinds amendments add, with their group: the Doors amendment (rulings 34.02, 34.06), and
|
|
251
|
+
* executor.turn_continued (lead ruling 2026-10-28: the seat sent its one automatic "continue" to a
|
|
252
|
+
* turn a lock interrupted). They are not in the design's §3.7 table, so DESIGN_EVENT_KINDS stays the
|
|
253
|
+
* design's table and these are listed here.
|
|
254
|
+
*/
|
|
255
|
+
export const AMENDMENT_EVENT_GROUPS = Object.freeze({
|
|
256
|
+
"session.ready": "lifecycle",
|
|
257
|
+
"session.waiting": "lifecycle",
|
|
258
|
+
"session.wait_cleared": "lifecycle",
|
|
259
|
+
"executor.turn_continued": "lease",
|
|
260
|
+
});
|
|
261
|
+
export function eventGroupOf(kind) {
|
|
262
|
+
if (Object.prototype.hasOwnProperty.call(AMENDMENT_EVENT_GROUPS, kind))
|
|
263
|
+
return AMENDMENT_EVENT_GROUPS[kind];
|
|
264
|
+
for (const g of EVENT_GROUPS)
|
|
265
|
+
if (DESIGN_EVENT_KINDS[g].includes(kind))
|
|
266
|
+
return g;
|
|
267
|
+
throw new Error(`unreachable: ${kind} has no group`);
|
|
268
|
+
}
|
|
269
|
+
export const EVENT_WRITERS = ["executor", "gateway", "api"];
|
|
270
|
+
/**
|
|
271
|
+
* M1: exactly [executor.spawned] (L01); the Doors amendment adds session.waiting (ruling 34.06), and
|
|
272
|
+
* the seat's one automatic continue adds executor.turn_continued (lead ruling 2026-10-28).
|
|
273
|
+
*/
|
|
274
|
+
export const EXECUTOR_WRITABLE_KINDS = [
|
|
275
|
+
"executor.spawned",
|
|
276
|
+
"session.waiting",
|
|
277
|
+
"executor.turn_continued",
|
|
278
|
+
];
|
|
279
|
+
/** Gateway: no session state in M1, so no containment.*, charter.* or lifecycle kind. */
|
|
280
|
+
export const GATEWAY_WRITABLE_KINDS = [
|
|
281
|
+
"lease.zombie_call",
|
|
282
|
+
"identity.mismatch",
|
|
283
|
+
"guard.unavailable",
|
|
284
|
+
];
|
|
285
|
+
/** The one writer class allowed to append a kind; everything not executor- or gateway-writable is API-writable. */
|
|
286
|
+
export function writerOf(kind) {
|
|
287
|
+
if (EXECUTOR_WRITABLE_KINDS.includes(kind))
|
|
288
|
+
return "executor";
|
|
289
|
+
if (GATEWAY_WRITABLE_KINDS.includes(kind))
|
|
290
|
+
return "gateway";
|
|
291
|
+
return "api";
|
|
292
|
+
}
|
|
293
|
+
/** Kinds with no M1 emitter: seeded for parity, never written by M1 code (C10-R4 static scan). */
|
|
294
|
+
export const NO_M1_EMITTER_KINDS = [
|
|
295
|
+
"session.resumed",
|
|
296
|
+
"session.moved",
|
|
297
|
+
"charter.goal_sealed",
|
|
298
|
+
"profile.amended",
|
|
299
|
+
"executor.upgraded",
|
|
300
|
+
"lease.stale_admit",
|
|
301
|
+
"executor.enrolled",
|
|
302
|
+
"executor.contract_violation",
|
|
303
|
+
"inbox.admitted",
|
|
304
|
+
"inbox.rejected",
|
|
305
|
+
"inbox.coalesced",
|
|
306
|
+
"inbox.held_unsealed",
|
|
307
|
+
"inbox.queued_for_home",
|
|
308
|
+
"inbox.reverted",
|
|
309
|
+
"inbox.delivered",
|
|
310
|
+
"inbox.unmatched",
|
|
311
|
+
"inbox.dead",
|
|
312
|
+
"timer.set",
|
|
313
|
+
"timer.fired",
|
|
314
|
+
"timer.cancelled",
|
|
315
|
+
"trigger.added",
|
|
316
|
+
"trigger.removed",
|
|
317
|
+
"trigger.fired",
|
|
318
|
+
"trigger.suppressed",
|
|
319
|
+
"trigger.over_cap",
|
|
320
|
+
"wake.undelivered",
|
|
321
|
+
"question.asked",
|
|
322
|
+
"question.answered",
|
|
323
|
+
"approval.superseded",
|
|
324
|
+
"approval.single_person_override",
|
|
325
|
+
"never.held",
|
|
326
|
+
"verdict.violation",
|
|
327
|
+
"containment.auto_pause",
|
|
328
|
+
"governance.degraded_admit",
|
|
329
|
+
"governance.outage_mode_set",
|
|
330
|
+
"policy.host_unattended_changed",
|
|
331
|
+
"workspace.checkpointed",
|
|
332
|
+
"rearm.recorded",
|
|
333
|
+
"tip.signed",
|
|
334
|
+
];
|
|
335
|
+
const UUID_PATTERN = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
|
|
336
|
+
const HEX12_PATTERN = "^[0-9a-f]{12}$";
|
|
337
|
+
const HEX64_PATTERN = "^[0-9a-f]{64}$";
|
|
338
|
+
const HEX40_PATTERN = "^[0-9a-f]{40}$";
|
|
339
|
+
const S = (extra = {}) => ({
|
|
340
|
+
type: "string",
|
|
341
|
+
maxLength: 64,
|
|
342
|
+
...extra,
|
|
343
|
+
});
|
|
344
|
+
const UUID = S({ pattern: UUID_PATTERN, maxLength: 36 });
|
|
345
|
+
const INT = (min = 0) => ({ type: "integer", minimum: min });
|
|
346
|
+
const ENUM = (values) => ({
|
|
347
|
+
type: "string",
|
|
348
|
+
enum: values,
|
|
349
|
+
maxLength: 64,
|
|
350
|
+
});
|
|
351
|
+
const obj = (properties, required = Object.keys(properties), if_then) => if_then
|
|
352
|
+
? { type: "object", additionalProperties: false, required, properties, if_then }
|
|
353
|
+
: { type: "object", additionalProperties: false, required, properties };
|
|
354
|
+
const EMPTY = obj({});
|
|
355
|
+
/** durable_approvals.kind values, as the approval.* refs enums carry them. */
|
|
356
|
+
export const APPROVAL_KINDS = [
|
|
357
|
+
"question",
|
|
358
|
+
"ask",
|
|
359
|
+
"tool_confirmation",
|
|
360
|
+
"intent_rerun",
|
|
361
|
+
"card_drift",
|
|
362
|
+
"owner_mutation",
|
|
363
|
+
"grant_renewal",
|
|
364
|
+
"limit_raise",
|
|
365
|
+
];
|
|
366
|
+
/** session.ready refs.cause: how a session entered ready (ruling 34.02 (3)). */
|
|
367
|
+
export const READY_CAUSES = ["dispatched", "lease_expired", "wait_cleared"];
|
|
368
|
+
// question joins the M1 four (ruling 34.06.1.1): its wait parks on an owner_mutation approval.
|
|
369
|
+
const OWNER_MUTATION_SUBJECTS = [
|
|
370
|
+
"unlock",
|
|
371
|
+
"unpause_contained",
|
|
372
|
+
"grant_renewal",
|
|
373
|
+
"budget_raise",
|
|
374
|
+
"question",
|
|
375
|
+
];
|
|
376
|
+
const KIND_REFS = {
|
|
377
|
+
"session.registered": obj({ durable_mode: ENUM(["tracked", "locked"]) }),
|
|
378
|
+
"session.locked": obj({ charter_version: INT(1) }),
|
|
379
|
+
"session.detached": obj({ reason: ENUM([...DETACHED_REASONS]) }),
|
|
380
|
+
"session.parked": obj({
|
|
381
|
+
from_state: ENUM(["resuming", "running", "detached", "suspended", "paused", "tracked"]),
|
|
382
|
+
}),
|
|
383
|
+
"session.suspended": obj({
|
|
384
|
+
reason: ENUM([...SUSPENDED_REASONS]),
|
|
385
|
+
check: ENUM([...ATTESTATION_CHECKS_M1]),
|
|
386
|
+
cause: ENUM([...CWD_CHECK_CAUSES]),
|
|
387
|
+
}, ["reason"]),
|
|
388
|
+
"session.paused": obj({ reason: ENUM([...PAUSED_REASONS]) }),
|
|
389
|
+
"session.unpaused": obj({
|
|
390
|
+
from_state: ENUM(["paused", "suspended"]),
|
|
391
|
+
from_reason: ENUM([
|
|
392
|
+
"owner",
|
|
393
|
+
"agent_contained",
|
|
394
|
+
"respawn_failed",
|
|
395
|
+
"attestation_failed",
|
|
396
|
+
"approval_expired",
|
|
397
|
+
"approval_denied",
|
|
398
|
+
]),
|
|
399
|
+
}, ["from_state", "from_reason"], [
|
|
400
|
+
{
|
|
401
|
+
field: "from_state",
|
|
402
|
+
equals: "paused",
|
|
403
|
+
enums: { from_reason: ["owner", "agent_contained"] },
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
field: "from_state",
|
|
407
|
+
equals: "suspended",
|
|
408
|
+
enums: {
|
|
409
|
+
from_reason: [
|
|
410
|
+
"respawn_failed",
|
|
411
|
+
"attestation_failed",
|
|
412
|
+
"approval_expired",
|
|
413
|
+
"approval_denied",
|
|
414
|
+
],
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
]),
|
|
418
|
+
"session.failed": obj({ reason: ENUM([...FAILED_REASONS]) }),
|
|
419
|
+
"session.killed": obj({ reason: ENUM(["owner", "agent_killed"]) }),
|
|
420
|
+
"seat.hello": obj({ spawn_id: UUID }),
|
|
421
|
+
"charter.sealed": obj({
|
|
422
|
+
charter_version: INT(1),
|
|
423
|
+
hash_prefix: S({ pattern: HEX12_PATTERN, maxLength: 12 }),
|
|
424
|
+
}),
|
|
425
|
+
"charter.amended": obj({ charter_version: INT(2), change: ENUM(["budget_raise", "lowering"]) }),
|
|
426
|
+
"charter.card_drift": obj({
|
|
427
|
+
direction: ENUM(["tighten", "loosen", "unknown"]),
|
|
428
|
+
observed_hash_prefix: S({ pattern: HEX12_PATTERN, maxLength: 12 }),
|
|
429
|
+
}),
|
|
430
|
+
"attestation.passed": obj({
|
|
431
|
+
cli_version: S({ pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?$", maxLength: 40 }),
|
|
432
|
+
plugin_hash: S({ pattern: HEX64_PATTERN, maxLength: 64 }),
|
|
433
|
+
renderer_version: INT(1),
|
|
434
|
+
}),
|
|
435
|
+
"attestation.failed": obj({ check: ENUM([...ATTESTATION_CHECKS_M1]), cause: ENUM([...CWD_CHECK_CAUSES]) }, ["check"]),
|
|
436
|
+
// ruling 34.03 (2): an acquire of a pool session carries pool: true
|
|
437
|
+
"lease.acquired": obj({ outcome: ENUM(["acquired", "epoch_bump"]), pool: { type: "boolean", const: true } }, ["outcome"]),
|
|
438
|
+
"lease.reclaimed": EMPTY,
|
|
439
|
+
"lease.released": EMPTY,
|
|
440
|
+
"lease.expired": EMPTY,
|
|
441
|
+
"lease.fenced": EMPTY,
|
|
442
|
+
"lease.zombie_call": obj({ admitted_epoch: INT(0), current_epoch: INT(0) }),
|
|
443
|
+
"executor.revoked": EMPTY,
|
|
444
|
+
"executor.spawned": obj({ spawn_id: UUID }),
|
|
445
|
+
"executor.exited": obj({
|
|
446
|
+
spawn_id: UUID,
|
|
447
|
+
exit_status: INT(0),
|
|
448
|
+
hello_accepted: { type: "boolean" },
|
|
449
|
+
}),
|
|
450
|
+
"approval.requested": obj({
|
|
451
|
+
approval_id: UUID,
|
|
452
|
+
approval_kind: ENUM(APPROVAL_KINDS),
|
|
453
|
+
subject: ENUM(OWNER_MUTATION_SUBJECTS),
|
|
454
|
+
}),
|
|
455
|
+
"approval.resolved": obj({
|
|
456
|
+
approval_id: UUID,
|
|
457
|
+
approval_kind: ENUM(APPROVAL_KINDS),
|
|
458
|
+
decision: ENUM(["approved", "denied"]),
|
|
459
|
+
}),
|
|
460
|
+
"approval.consumed": obj({
|
|
461
|
+
approval_id: UUID,
|
|
462
|
+
approval_kind: ENUM(APPROVAL_KINDS),
|
|
463
|
+
subject_hash: S({ pattern: HEX64_PATTERN, maxLength: 64 }),
|
|
464
|
+
sh_decision_id: UUID,
|
|
465
|
+
}, ["approval_id", "approval_kind", "subject_hash"], [{ field: "approval_kind", equals: "tool_confirmation", require: ["sh_decision_id"] }]),
|
|
466
|
+
"approval.expired": obj({ approval_id: UUID, approval_kind: ENUM(APPROVAL_KINDS) }),
|
|
467
|
+
"chain.posture": obj({ posture: ENUM(["attended", "unattended"]) }),
|
|
468
|
+
"guard.refused": obj({ sh_decision_id: UUID }, []),
|
|
469
|
+
"guard.unavailable": EMPTY,
|
|
470
|
+
"budget.reached": EMPTY,
|
|
471
|
+
"grant.renewed": obj({ approval_id: UUID }),
|
|
472
|
+
"grant.revoked": EMPTY,
|
|
473
|
+
"identity.mismatch": obj({
|
|
474
|
+
expected_agent_hash_prefix: S({ pattern: HEX12_PATTERN, maxLength: 12 }),
|
|
475
|
+
presented: ENUM(["absent", "mismatch"]),
|
|
476
|
+
}),
|
|
477
|
+
"containment.pause": obj({ action: ENUM(["pause"]) }),
|
|
478
|
+
"containment.kill": obj({ action: ENUM(["kill"]) }),
|
|
479
|
+
"never.held": obj({ sh_decision_id: UUID }),
|
|
480
|
+
// ---- Doors amendment (rulings 34.02, 34.06) ----
|
|
481
|
+
"session.ready": obj({ cause: ENUM(READY_CAUSES) }),
|
|
482
|
+
"session.waiting": obj({
|
|
483
|
+
wait_reason: ENUM(PARKED_ONLY_WAIT_REASONS),
|
|
484
|
+
head_sha: S({ pattern: HEX40_PATTERN, maxLength: 40 }),
|
|
485
|
+
approval_id: UUID,
|
|
486
|
+
}, ["wait_reason"], [
|
|
487
|
+
{ field: "wait_reason", equals: "ci", require: ["head_sha"], forbid: ["approval_id"] },
|
|
488
|
+
{ field: "wait_reason", equals: "question", require: ["approval_id"], forbid: ["head_sha"] },
|
|
489
|
+
{ field: "wait_reason", equals: "budget", require: ["approval_id"], forbid: ["head_sha"] },
|
|
490
|
+
]),
|
|
491
|
+
"session.wait_cleared": obj({ wait_reason: ENUM(PARKED_ONLY_WAIT_REASONS) }),
|
|
492
|
+
// ---- lead ruling 2026-10-28: the spawn that sent the continue; a separate fact, so
|
|
493
|
+
// executor.spawned's refs stay exactly {spawn_id} ----
|
|
494
|
+
"executor.turn_continued": obj({ spawn_id: UUID }),
|
|
495
|
+
};
|
|
496
|
+
/** refs_schema for every M1 kind; kinds without a specific schema take EMPTY (refs must be {}). */
|
|
497
|
+
export function refsSchemaOf(kind) {
|
|
498
|
+
return KIND_REFS[kind] ?? EMPTY;
|
|
499
|
+
}
|
|
500
|
+
/** One refs property against its schema (pure; exported for its direct test). An integer with no minimum accepts any safe integer. */
|
|
501
|
+
export function refsPropertyOk(p, v) {
|
|
502
|
+
if (p.type === "boolean")
|
|
503
|
+
return typeof v === "boolean" && (p.const === undefined || v === p.const);
|
|
504
|
+
if (p.type === "integer")
|
|
505
|
+
return Number.isSafeInteger(v) && v >= (p.minimum ?? Number.MIN_SAFE_INTEGER);
|
|
506
|
+
if (typeof v !== "string")
|
|
507
|
+
return false;
|
|
508
|
+
if (p.maxLength !== undefined && v.length > p.maxLength)
|
|
509
|
+
return false;
|
|
510
|
+
if (p.enum !== undefined && !p.enum.includes(v))
|
|
511
|
+
return false;
|
|
512
|
+
return p.pattern === undefined || new RegExp(p.pattern).test(v);
|
|
513
|
+
}
|
|
514
|
+
/** Reference validator for refs against refsSchemaOf(kind) (the RPC enforces the same rules). */
|
|
515
|
+
export function validateRefs(kind, refs) {
|
|
516
|
+
if (refs === null || typeof refs !== "object" || Array.isArray(refs))
|
|
517
|
+
return false;
|
|
518
|
+
const schema = refsSchemaOf(kind);
|
|
519
|
+
const r = refs;
|
|
520
|
+
for (const key of Object.keys(r)) {
|
|
521
|
+
const p = schema.properties[key];
|
|
522
|
+
if (p === undefined || !refsPropertyOk(p, r[key]))
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
if (!schema.required.every((k) => k in r))
|
|
526
|
+
return false;
|
|
527
|
+
for (const rule of schema.if_then ?? []) {
|
|
528
|
+
if (r[rule.field] !== rule.equals)
|
|
529
|
+
continue;
|
|
530
|
+
if (rule.require && !rule.require.every((k) => k in r))
|
|
531
|
+
return false;
|
|
532
|
+
if (rule.forbid && rule.forbid.some((k) => k in r))
|
|
533
|
+
return false;
|
|
534
|
+
for (const [field, allowed] of Object.entries(rule.enums ?? {})) {
|
|
535
|
+
if (!allowed.includes(r[field]))
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
/** Server-generated detail (C10-R6, C18-R07): "<kind>" then " key=value" for each refs key, sorted. Content-free by construction. */
|
|
542
|
+
export function eventDetail(kind, refs) {
|
|
543
|
+
const parts = Object.keys(refs)
|
|
544
|
+
.sort()
|
|
545
|
+
.map((k) => `${k}=${refs[k] === null ? "null" : String(refs[k])}`);
|
|
546
|
+
const text = [kind, ...parts].join(" ");
|
|
547
|
+
if (text.length > EVENT_DETAIL_MAX_CHARS)
|
|
548
|
+
throw new RangeError(`detail over ${EVENT_DETAIL_MAX_CHARS} chars`);
|
|
549
|
+
return text;
|
|
550
|
+
}
|
|
551
|
+
/** The closed shape every stored detail matches (the C18 structural checker's regex). */
|
|
552
|
+
export const EVENT_DETAIL_RE = /^[a-z_]+\.[a-z_]+( [a-z_]+=[A-Za-z0-9_.:-]+)*$/;
|
|
553
|
+
// ---- idempotency keys -------------------------------------------------------------------------
|
|
554
|
+
export const idempotencyKeys = {
|
|
555
|
+
spawn: (sessionId, epoch, spawnId) => `spawn:${sessionId}:${epoch}:${spawnId}`,
|
|
556
|
+
zombie: (requestId) => `zombie:${requestId}`,
|
|
557
|
+
identityMismatch: (sessionId, epoch) => `idmm:${sessionId}:${epoch}`,
|
|
558
|
+
cardDrift: (sessionId, observedHash) => `drift:${sessionId}:${observedHash}`,
|
|
559
|
+
/** API transitions: one event per (session, kind, new epoch); a retried transition replays the row. */
|
|
560
|
+
transition: (sessionId, kind, epoch) => `tr:${sessionId}:${kind}:${epoch}`,
|
|
561
|
+
};
|
|
562
|
+
// ---- preimage ---------------------------------------------------------------------------------
|
|
563
|
+
export const GENESIS_PREV_HASH = "0".repeat(64);
|
|
564
|
+
export const GATEWAY_EVENTS_ROUTE = "/internal/durable/events";
|
|
565
|
+
/**
|
|
566
|
+
* The journal kinds that mark a terminal transition, one per TERMINAL_STATES value in the same
|
|
567
|
+
* order (wave-0 fix ruling 1.06). contract_purge_after is stamped from the ts of this event
|
|
568
|
+
* (C18-R13).
|
|
569
|
+
*/
|
|
570
|
+
export const TERMINAL_EVENT_KINDS = [
|
|
571
|
+
"session.completed",
|
|
572
|
+
"session.failed",
|
|
573
|
+
"session.killed",
|
|
574
|
+
"session.expired",
|
|
575
|
+
];
|
|
576
|
+
export const EVENT_DSR = { phase: "user_erasure", treatment: "pseudonymize" };
|
|
577
|
+
/** Hashed fields, in no particular order (canonicalJson sorts). Raw detail, refs and principal_uid are never hashed. */
|
|
578
|
+
export const EVENT_PREIMAGE_FIELDS = [
|
|
579
|
+
"v",
|
|
580
|
+
"session_id",
|
|
581
|
+
"seq",
|
|
582
|
+
"ts",
|
|
583
|
+
"kind",
|
|
584
|
+
"epoch",
|
|
585
|
+
"idempotency_key",
|
|
586
|
+
"principal_ref",
|
|
587
|
+
"detail_sha256",
|
|
588
|
+
"refs_sha256",
|
|
589
|
+
"prev_hash",
|
|
590
|
+
];
|
|
591
|
+
const TS_RE = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}:\d{2})(?:\.(\d{1,6}))?(Z|[+-]00(?::?00)?)$/;
|
|
592
|
+
/** The canonical ts text: UTC, 6 fraction digits, "Z". Throws on a non-UTC or malformed value. */
|
|
593
|
+
export function canonicalEventTs(ts) {
|
|
594
|
+
const m = TS_RE.exec(ts);
|
|
595
|
+
if (!m)
|
|
596
|
+
throw new RangeError(`not a UTC timestamp: ${ts}`);
|
|
597
|
+
return `${m[1]}T${m[2]}.${(m[3] ?? "").padEnd(6, "0")}Z`;
|
|
598
|
+
}
|
|
599
|
+
/** The API's stamper: millisecond Date, canonical form. */
|
|
600
|
+
export function stampEventTs(epochMs) {
|
|
601
|
+
return canonicalEventTs(new Date(epochMs).toISOString());
|
|
602
|
+
}
|
|
603
|
+
/** The preimage object; absent principal_ref hashes like explicit null (C10-R8). */
|
|
604
|
+
export function eventPreimage(input) {
|
|
605
|
+
if (!HEX64_RE.test(input.prev_hash))
|
|
606
|
+
throw new RangeError("prev_hash must be 64 lowercase hex");
|
|
607
|
+
return {
|
|
608
|
+
v: 1,
|
|
609
|
+
session_id: input.session_id,
|
|
610
|
+
seq: input.seq,
|
|
611
|
+
ts: canonicalEventTs(input.ts),
|
|
612
|
+
kind: input.kind,
|
|
613
|
+
epoch: input.epoch,
|
|
614
|
+
idempotency_key: input.idempotency_key,
|
|
615
|
+
principal_ref: input.principal_ref ?? null,
|
|
616
|
+
detail_sha256: input.detail_sha256,
|
|
617
|
+
refs_sha256: input.refs_sha256,
|
|
618
|
+
prev_hash: input.prev_hash,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
export async function eventHash(input) {
|
|
622
|
+
return sha256Hex(canonicalJson(eventPreimage(input)));
|
|
623
|
+
}
|
|
624
|
+
export async function refsSha256(refs) {
|
|
625
|
+
return sha256Hex(canonicalJson(refs));
|
|
626
|
+
}
|
|
627
|
+
/** principal_ref = HMAC-SHA256(hmac_salt, principal_uid), lowercase hex (C10-R15). */
|
|
628
|
+
export async function principalRef(hmacSalt, principalUid) {
|
|
629
|
+
return hmacSha256Hex(hmacSalt, principalUid);
|
|
630
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The executor state file's shape (wave-0 fix ruling 24.14; C12-R05). EXECUTOR_STATE_FILE holds the
|
|
3
|
+
* executor key, the executor id, the nonce and the boot id the nonce is bound to, as one closed
|
|
4
|
+
* object. The host instance name is deliberately absent (C12-R04: read from config/env, so a copied
|
|
5
|
+
* file does not carry it). Internal: customers never read or edit this file; its location
|
|
6
|
+
* (paths.ts) is the customer-facing part.
|
|
7
|
+
*/
|
|
8
|
+
export declare const EXECUTOR_STATE_VERSION = 1;
|
|
9
|
+
/** Field order is the file's key order. version is the integer EXECUTOR_STATE_VERSION. */
|
|
10
|
+
export declare const EXECUTOR_STATE_SCHEMA: Readonly<{
|
|
11
|
+
readonly version: {
|
|
12
|
+
readonly type: "integer";
|
|
13
|
+
readonly nullable: false;
|
|
14
|
+
};
|
|
15
|
+
readonly executor_id: {
|
|
16
|
+
readonly type: "uuid";
|
|
17
|
+
readonly nullable: false;
|
|
18
|
+
};
|
|
19
|
+
/** The SECRET_KINDS executor_key spelling; this file is its only allowed home. */
|
|
20
|
+
readonly executor_key: {
|
|
21
|
+
readonly type: "string";
|
|
22
|
+
readonly nullable: false;
|
|
23
|
+
};
|
|
24
|
+
readonly nonce: {
|
|
25
|
+
readonly type: "string";
|
|
26
|
+
readonly nullable: false;
|
|
27
|
+
};
|
|
28
|
+
readonly boot_id: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
readonly nullable: false;
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
33
|
+
export interface ExecutorState {
|
|
34
|
+
readonly version: typeof EXECUTOR_STATE_VERSION;
|
|
35
|
+
readonly executor_id: string;
|
|
36
|
+
readonly executor_key: string;
|
|
37
|
+
readonly nonce: string;
|
|
38
|
+
readonly boot_id: string;
|
|
39
|
+
}
|
|
40
|
+
/** True for exactly the frozen shape: every key present and well typed, no other key, version 1. */
|
|
41
|
+
export declare function executorStateOk(v: unknown): v is ExecutorState;
|