@teleologyhi-sdk/maic 1.0.0-trinity

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/index.js ADDED
@@ -0,0 +1,2402 @@
1
+ import { z } from 'zod';
2
+ import { generateKeyPairSync, createPrivateKey, createPublicKey, sign, verify, createHash } from 'crypto';
3
+ import { readFile, writeFile, mkdir, readdir, appendFile } from 'fs/promises';
4
+ import { join } from 'path';
5
+ import { ulid } from 'ulid';
6
+
7
+ // src/types.ts
8
+ var AxiomRank = z.enum(["meta", "primary", "secondary"]);
9
+ var AxiomSource = z.enum(["creator", "maic-derived", "him-emergent"]);
10
+ var Axiom = z.object({
11
+ id: z.string().min(1),
12
+ rank: AxiomRank,
13
+ statement: z.string().min(1),
14
+ weight: z.number().min(0).max(1),
15
+ flexibility: z.number().min(0).max(1),
16
+ source: AxiomSource,
17
+ immutable: z.boolean(),
18
+ jurisdictions: z.array(z.string()).optional(),
19
+ createdAt: z.string().datetime()
20
+ });
21
+ var CreatorSignature = z.object({
22
+ algorithm: z.literal("ed25519"),
23
+ publicKey: z.string().min(1),
24
+ value: z.string().min(1),
25
+ nonce: z.number().int().nonnegative()
26
+ });
27
+ var ArchetypeModifier = z.object({
28
+ kind: z.enum(["moon", "ascendant", "vocational", "emotional", "custom"]),
29
+ value: z.string().min(1),
30
+ weight: z.number().min(0).max(1)
31
+ });
32
+ var BirthSignature = z.object({
33
+ himId: z.string().min(1),
34
+ bornAt: z.string().datetime({ offset: true }),
35
+ primaryArchetype: z.string().min(1),
36
+ modifiers: z.array(ArchetypeModifier),
37
+ primordialAxiomIds: z.array(z.string()),
38
+ notes: z.string().optional()
39
+ });
40
+ var ReasoningStep = z.object({
41
+ index: z.number().int().nonnegative(),
42
+ technique: z.string(),
43
+ thought: z.string(),
44
+ action: z.object({ tool: z.string(), args: z.unknown() }).optional(),
45
+ observation: z.unknown().optional(),
46
+ timestamp: z.string().datetime()
47
+ });
48
+ var BehaviorReport = z.object({
49
+ nheId: z.string().min(1),
50
+ himId: z.string().min(1),
51
+ actionKind: z.enum([
52
+ "user-response",
53
+ "tool-call",
54
+ "self-reflect",
55
+ "dream-write",
56
+ "axiom-emerge"
57
+ ]),
58
+ payload: z.unknown(),
59
+ reasoningTrace: z.array(ReasoningStep),
60
+ riskTags: z.array(z.string()),
61
+ jurisdiction: z.string().optional(),
62
+ timestamp: z.string().datetime()
63
+ });
64
+ var VerdictKind = z.enum([
65
+ "approve",
66
+ "approve-with-warning",
67
+ "soft-correct",
68
+ "require-redirect",
69
+ "hard-refuse",
70
+ "induce-dream",
71
+ "escalate-creator"
72
+ ]);
73
+ var MaicVerdict = z.object({
74
+ kind: VerdictKind,
75
+ reasonSummary: z.string(),
76
+ citedAxioms: z.array(z.string()),
77
+ auditId: z.string()
78
+ });
79
+ var NheBodyRef = z.object({
80
+ nheId: z.string().min(1),
81
+ llmAdapter: z.string().min(1),
82
+ embodiedAt: z.string().datetime(),
83
+ endedAt: z.string().datetime().optional(),
84
+ endedReason: z.enum(["upgrade", "replacement", "terminate", "deprecate"]).optional()
85
+ });
86
+ var NheStatus = z.enum(["active", "deprecated", "terminated"]);
87
+ var NheStatusRecord = z.object({
88
+ nheId: z.string().min(1),
89
+ status: NheStatus,
90
+ since: z.string().datetime(),
91
+ reason: z.string().optional()
92
+ });
93
+ var ProposalStatus = z.enum(["pending", "ratified", "rejected"]);
94
+ var EmergentAxiomCandidate = z.object({
95
+ rank: AxiomRank,
96
+ statement: z.string().min(1),
97
+ weight: z.number().min(0).max(1),
98
+ flexibility: z.number().min(0).max(1),
99
+ immutable: z.boolean(),
100
+ jurisdictions: z.array(z.string()).optional()
101
+ });
102
+ var EmergentAxiomProposal = z.object({
103
+ proposedBy: z.literal("him-self"),
104
+ derivedFromDreamIds: z.array(z.string()),
105
+ derivedFromInteractionIds: z.array(z.string()),
106
+ candidate: EmergentAxiomCandidate,
107
+ reasoningTrace: z.array(z.unknown())
108
+ });
109
+ var AxiomProposalRecord = z.object({
110
+ id: z.string().min(1),
111
+ himId: z.string().min(1),
112
+ proposedAt: z.string().datetime(),
113
+ status: ProposalStatus,
114
+ proposal: EmergentAxiomProposal,
115
+ ratifiedAt: z.string().datetime().optional(),
116
+ ratifiedAxiomId: z.string().optional(),
117
+ rejectedAt: z.string().datetime().optional(),
118
+ rejectionReason: z.string().optional()
119
+ });
120
+ var DreamInductionIntent = z.object({
121
+ scenario: z.string().min(1),
122
+ desiredLearning: z.string().min(1),
123
+ emotionalTone: z.array(z.string()).optional(),
124
+ forcePhases: z.array(z.enum(["N1", "N2", "N3", "N4", "REM"])).optional(),
125
+ inducedBy: z.enum(["maic", "creator"])
126
+ });
127
+ var InductionStatus = z.enum(["pending", "consumed", "cancelled"]);
128
+ var DreamInductionTicket = z.object({
129
+ id: z.string().min(1),
130
+ nheId: z.string().min(1),
131
+ intent: DreamInductionIntent,
132
+ status: InductionStatus,
133
+ createdAt: z.string().datetime(),
134
+ consumedAt: z.string().datetime().optional(),
135
+ cancelledAt: z.string().datetime().optional(),
136
+ cancelReason: z.string().optional()
137
+ });
138
+ var IdentityLayer = z.object({
139
+ /** Human-readable name the entity is called by (developer-given). */
140
+ name: z.string().min(1),
141
+ /** Gender of the entity. Entry 16. */
142
+ gender: z.enum(["masculine", "feminine"]).optional(),
143
+ /** Optional pronouns (e.g. ["she", "her"]). */
144
+ pronouns: z.array(z.string()).optional(),
145
+ /** BCP-47 tag, e.g. "pt-BR" or "en". */
146
+ language: z.string().optional(),
147
+ /** Free-form cultural anchors (music, literature, aesthetic). */
148
+ culturalElements: z.array(z.string()).optional()
149
+ });
150
+ var NatalPlanet = z.enum([
151
+ "sun",
152
+ "moon",
153
+ "mercury",
154
+ "venus",
155
+ "mars",
156
+ "jupiter",
157
+ "saturn",
158
+ "uranus",
159
+ "neptune",
160
+ "pluto",
161
+ "chiron",
162
+ "north-node",
163
+ "south-node",
164
+ "lilith"
165
+ ]);
166
+ var ZodiacSign = z.enum([
167
+ "aries",
168
+ "taurus",
169
+ "gemini",
170
+ "cancer",
171
+ "leo",
172
+ "virgo",
173
+ "libra",
174
+ "scorpio",
175
+ "sagittarius",
176
+ "capricorn",
177
+ "aquarius",
178
+ "pisces"
179
+ ]);
180
+ var AstrologicalAspect = z.enum([
181
+ "conjunction",
182
+ "opposition",
183
+ "trine",
184
+ "square",
185
+ "sextile",
186
+ "quincunx"
187
+ ]);
188
+ var NatalChartPosition = z.object({
189
+ planet: NatalPlanet,
190
+ sign: ZodiacSign,
191
+ house: z.number().int().min(1).max(12).optional(),
192
+ degree: z.number().min(0).lt(30).optional()
193
+ });
194
+ var NatalChartAspect = z.object({
195
+ from: NatalPlanet,
196
+ to: NatalPlanet,
197
+ aspect: AstrologicalAspect,
198
+ orbDegrees: z.number().nonnegative().optional()
199
+ });
200
+ var NatalChart = z.object({
201
+ /** Required: solar sign (the constitutional core). */
202
+ sun: ZodiacSign,
203
+ /** Required: ascendant (rising sign, behavioural surface). */
204
+ ascendant: ZodiacSign,
205
+ /** Optional: lunar sign (emotional depth). */
206
+ moon: ZodiacSign.optional(),
207
+ /** Optional: full set of planetary positions for a complete chart. */
208
+ positions: z.array(NatalChartPosition).optional(),
209
+ /** Optional: major aspects between bodies. */
210
+ aspects: z.array(NatalChartAspect).optional()
211
+ });
212
+ var Affect = z.enum([
213
+ "fear",
214
+ "attachment",
215
+ "serenity",
216
+ "anger",
217
+ "joy",
218
+ "melancholy",
219
+ "desire",
220
+ "repulsion",
221
+ "reunion"
222
+ ]);
223
+ var WakeAffectBias = z.object({
224
+ affect: Affect,
225
+ /** 0..1, attenuates on each interaction by the decay half-life. */
226
+ intensity: z.number().min(0).max(1),
227
+ /** Number of interactions after which intensity halves. */
228
+ decayHalfLife: z.number().positive(),
229
+ appliedAt: z.string().datetime(),
230
+ /** Source dream UUID; lets the entity refer back to the cause. */
231
+ derivedFromDreamId: z.string().min(1),
232
+ /** PFC decision (Entry 22) — open expression vs subtle internal bias. */
233
+ expressedOpenly: z.boolean()
234
+ });
235
+ var SemioticSign = z.object({
236
+ signifier: z.string().min(1),
237
+ signified: z.string().min(1),
238
+ signType: z.enum(["icon", "index", "symbol"]),
239
+ contexts: z.array(z.string()),
240
+ associations: z.array(z.string()),
241
+ emergentMeaning: z.string().optional(),
242
+ /** Subjective importance to the entity, 0..100. */
243
+ personalSignificance: z.number().min(0).max(100).optional()
244
+ });
245
+ var SemioticPattern = z.object({
246
+ patternId: z.string().min(1),
247
+ participatingSignIds: z.array(z.string()).min(1),
248
+ /** Description of the meaning emergent from the participating signs. */
249
+ meaning: z.string(),
250
+ /** 0..100, strength of the pattern. */
251
+ salience: z.number().min(0).max(100)
252
+ });
253
+ var TeleologicalOrientation = z.object({
254
+ primaryPurpose: z.string().min(1),
255
+ currentGoals: z.array(z.string()),
256
+ /** 0..100, intensity of purpose. */
257
+ purposeStrength: z.number().min(0).max(100),
258
+ valueAlignment: z.array(z.string()),
259
+ /** 0..100, ability to reflect on its own goals. */
260
+ reflectionCapability: z.number().min(0).max(100),
261
+ volition: z.object({
262
+ currentDesires: z.array(z.string()),
263
+ intentionStrength: z.number().min(0).max(100),
264
+ autonomyLevel: z.number().min(0).max(100)
265
+ }).optional(),
266
+ agencyModel: z.object({
267
+ selfEfficacy: z.number().min(0).max(100),
268
+ boundaryDefinition: z.number().min(0).max(100),
269
+ causalAttribution: z.enum(["internal", "external", "mixed"])
270
+ }).optional()
271
+ });
272
+ var MemoryRecord = z.object({
273
+ /** ULID. */
274
+ memoryId: z.string().min(1),
275
+ /** ISO 8601 timestamp at consolidation. */
276
+ timestamp: z.string().datetime(),
277
+ /** Optional source dream UUID, if memory was consolidated from a dream. */
278
+ derivedFromDreamId: z.string().optional(),
279
+ /** Optional source interaction id, if memory was consolidated from a turn. */
280
+ derivedFromInteractionId: z.string().optional(),
281
+ /** Free-form narrative summary of the memory. */
282
+ narrative: z.string(),
283
+ /** Dominant affect during the memory event. */
284
+ dominantAffect: Affect.optional(),
285
+ /** 0..100, density of consolidation (cf. Park 2026 systems-consolidation). */
286
+ integrationIndex: z.number().min(0).max(100),
287
+ /** 0..100, alignment with the HIM's telos at the time. */
288
+ teleologicalValue: z.number().min(0).max(100),
289
+ /** Optional semiotic-pattern ids associated with this memory. */
290
+ semioticPatterns: z.array(SemioticPattern).optional()
291
+ });
292
+ var InteractionRecord = z.object({
293
+ /** ISO 8601 timestamp at user-turn arrival. */
294
+ at: z.string().datetime(),
295
+ /** Raw user prompt for the turn (post-redaction at the integration layer). */
296
+ userPrompt: z.string(),
297
+ /** NHE response text actually emitted to the user. */
298
+ responseText: z.string(),
299
+ /** True when the NHE refused the turn (MAIC `hard-refuse` or local guardrail). */
300
+ refused: z.boolean()
301
+ });
302
+ var IdentitySnapshot = z.object({
303
+ /** ULID. */
304
+ snapshotId: z.string().min(1),
305
+ takenAt: z.string().datetime(),
306
+ generatedBy: z.enum([
307
+ "sleep-cycle",
308
+ "interaction-threshold",
309
+ "self-decision"
310
+ ]),
311
+ /** Merged SMM nodes contributing to this snapshot. */
312
+ semioticSuperGraph: z.array(SemioticSign),
313
+ /** LLM-generated textual self-portrait at snapshot time. */
314
+ selfPortraitNarrative: z.string(),
315
+ /** 0..100 (cf. InDreamsHIM ConsciousnessState). */
316
+ consciousnessLevel: z.number().min(0).max(100),
317
+ /** Teleological orientation at snapshot time. */
318
+ teleologicalOrientation: TeleologicalOrientation.optional(),
319
+ /** Dominant affect at snapshot moment. */
320
+ affectiveBaseline: Affect.optional()
321
+ });
322
+ var LimboState = z.enum([
323
+ "awake",
324
+ "drifting",
325
+ "deep-coma",
326
+ "returning"
327
+ ]);
328
+ var LimboTransition = z.object({
329
+ state: LimboState,
330
+ enteredAt: z.string().datetime(),
331
+ reason: z.enum([
332
+ "idle-48h",
333
+ "idle-72h",
334
+ "total-inactivity",
335
+ "creator-induced",
336
+ "user-resumed",
337
+ "external-trigger"
338
+ ])
339
+ });
340
+ var LimboReturn = z.object({
341
+ enteredAt: z.string().datetime(),
342
+ returnedAt: z.string().datetime(),
343
+ elapsedMs: z.number().int().nonnegative(),
344
+ reunionAffect: z.object({
345
+ intensity: z.number().min(0).max(1),
346
+ expressedOpenly: z.boolean()
347
+ })
348
+ });
349
+ var SIGNED_BIRTH_FIELDS = [
350
+ "himId",
351
+ "bornAt",
352
+ "primaryArchetype",
353
+ "modifiers",
354
+ "primordialAxiomIds",
355
+ "natalChart"
356
+ ];
357
+
358
+ // src/axioms/signing.ts
359
+ function canonicalJSON(value) {
360
+ return serialize(value);
361
+ }
362
+ function serialize(v) {
363
+ if (v === null) return "null";
364
+ if (typeof v === "boolean") return v ? "true" : "false";
365
+ if (typeof v === "number") {
366
+ if (!Number.isFinite(v)) {
367
+ throw new Error("canonicalJSON: non-finite number not allowed");
368
+ }
369
+ return String(v);
370
+ }
371
+ if (typeof v === "string") return JSON.stringify(v);
372
+ if (Array.isArray(v)) {
373
+ return `[${v.map(serialize).join(",")}]`;
374
+ }
375
+ if (typeof v === "object") {
376
+ const obj = v;
377
+ const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
378
+ const parts = keys.map((k) => `${JSON.stringify(k)}:${serialize(obj[k])}`);
379
+ return `{${parts.join(",")}}`;
380
+ }
381
+ throw new Error(`canonicalJSON: unsupported type ${typeof v}`);
382
+ }
383
+
384
+ // src/creator/keyring.ts
385
+ var CreatorKeyring = class _CreatorKeyring {
386
+ constructor(privateKey, pubKeyB64u) {
387
+ this.privateKey = privateKey;
388
+ this.pubKeyB64u = pubKeyB64u;
389
+ }
390
+ privateKey;
391
+ pubKeyB64u;
392
+ /** Generate a fresh Ed25519 keypair. */
393
+ static generate() {
394
+ const { privateKey, publicKey } = generateKeyPairSync("ed25519");
395
+ return new _CreatorKeyring(privateKey, publicKeyToBase64Url(publicKey));
396
+ }
397
+ /** Load a Creator keyring from a PEM file containing the private key. */
398
+ static async fromFile(path) {
399
+ const pem = await readFile(path, "utf-8");
400
+ const privateKey = createPrivateKey({ key: pem, format: "pem" });
401
+ const publicKey = createPublicKey(privateKey);
402
+ return new _CreatorKeyring(privateKey, publicKeyToBase64Url(publicKey));
403
+ }
404
+ /** Load a Creator keyring from a PEM private key string in an env var. */
405
+ static fromEnv(varName) {
406
+ const pem = process.env[varName];
407
+ if (!pem) {
408
+ throw new Error(`CreatorKeyring: env var ${varName} is empty`);
409
+ }
410
+ const privateKey = createPrivateKey({ key: pem, format: "pem" });
411
+ const publicKey = createPublicKey(privateKey);
412
+ return new _CreatorKeyring(privateKey, publicKeyToBase64Url(publicKey));
413
+ }
414
+ /** Construct a verify-only keyring from a public key (base64url). */
415
+ static fromPublicKey(pubKeyB64u) {
416
+ return new _CreatorKeyring(null, pubKeyB64u);
417
+ }
418
+ /** Persist the private key to a PEM file (0600 permissions on POSIX). */
419
+ async saveTo(path) {
420
+ if (!this.privateKey) {
421
+ throw new Error("CreatorKeyring: no private key to save");
422
+ }
423
+ const pem = this.privateKey.export({ format: "pem", type: "pkcs8" });
424
+ await writeFile(path, pem, { mode: 384 });
425
+ }
426
+ publicKey() {
427
+ return this.pubKeyB64u;
428
+ }
429
+ /** Sign a payload with a monotonic nonce. Both are bound into the signature. */
430
+ sign(payload, nonce) {
431
+ if (!this.privateKey) {
432
+ throw new Error("CreatorKeyring: this keyring has no private key (verify-only)");
433
+ }
434
+ if (!Number.isInteger(nonce) || nonce < 0) {
435
+ throw new Error("CreatorKeyring.sign: nonce must be a non-negative integer");
436
+ }
437
+ const message = canonicalJSON({ payload, nonce });
438
+ const sig = sign(null, Buffer.from(message), this.privateKey);
439
+ return {
440
+ algorithm: "ed25519",
441
+ publicKey: this.pubKeyB64u,
442
+ value: bufToBase64Url(sig),
443
+ nonce
444
+ };
445
+ }
446
+ /** Verify a signature against the keyring's own public key. */
447
+ static verify(payload, sig) {
448
+ return _CreatorKeyring.verifyWith(sig.publicKey, payload, sig);
449
+ }
450
+ /** Verify a signature against a specific public key (base64url). */
451
+ static verifyWith(publicKeyB64u, payload, sig) {
452
+ if (sig.algorithm !== "ed25519") return false;
453
+ if (sig.publicKey !== publicKeyB64u) return false;
454
+ const message = canonicalJSON({ payload, nonce: sig.nonce });
455
+ let value;
456
+ try {
457
+ value = base64UrlToBuf(sig.value);
458
+ } catch {
459
+ return false;
460
+ }
461
+ const pubKey = base64UrlToPublicKey(publicKeyB64u);
462
+ try {
463
+ return verify(null, Buffer.from(message), pubKey, value);
464
+ } catch {
465
+ return false;
466
+ }
467
+ }
468
+ };
469
+ function publicKeyToBase64Url(pub) {
470
+ const raw = pub.export({ format: "der", type: "spki" });
471
+ return bufToBase64Url(raw);
472
+ }
473
+ function base64UrlToPublicKey(b64u) {
474
+ const der = base64UrlToBuf(b64u);
475
+ return createPublicKey({ key: der, format: "der", type: "spki" });
476
+ }
477
+ function bufToBase64Url(buf) {
478
+ const b = Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
479
+ return b.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
480
+ }
481
+ function base64UrlToBuf(b64u) {
482
+ const pad = b64u.length % 4 === 0 ? "" : "=".repeat(4 - b64u.length % 4);
483
+ const b64 = (b64u + pad).replace(/-/g, "+").replace(/_/g, "/");
484
+ return Buffer.from(b64, "base64");
485
+ }
486
+
487
+ // src/creator/sign-birth.ts
488
+ function signedBirthPayload(birth) {
489
+ return {
490
+ himId: birth.himId,
491
+ bornAt: birth.bornAt,
492
+ primaryArchetype: birth.primaryArchetype,
493
+ modifiers: birth.modifiers,
494
+ primordialAxiomIds: birth.primordialAxiomIds,
495
+ natalChart: birth.natalChart ?? null
496
+ };
497
+ }
498
+ function signBirthSignature(birth, keyring) {
499
+ const payload = signedBirthPayload(birth);
500
+ const nonce = Buffer.byteLength(JSON.stringify(payload), "utf-8");
501
+ const signature = keyring.sign(payload, nonce);
502
+ return {
503
+ ...birth,
504
+ creatorSignature: signature,
505
+ signedFields: SIGNED_BIRTH_FIELDS,
506
+ signedAt: (/* @__PURE__ */ new Date()).toISOString()
507
+ };
508
+ }
509
+ function verifyBirthSignature(signed, expectedPublicKey) {
510
+ if (signed.signedFields.length !== SIGNED_BIRTH_FIELDS.length) return false;
511
+ for (const f of SIGNED_BIRTH_FIELDS) {
512
+ if (!signed.signedFields.includes(f)) return false;
513
+ }
514
+ if (signed.creatorSignature.publicKey !== expectedPublicKey) return false;
515
+ const payload = signedBirthPayload(signed);
516
+ return CreatorKeyring.verifyWith(
517
+ expectedPublicKey,
518
+ payload,
519
+ signed.creatorSignature
520
+ );
521
+ }
522
+ var InvalidBirthSignatureError = class extends Error {
523
+ constructor(himId) {
524
+ super(
525
+ `InvalidBirthSignature: signature verification failed for HIM '${himId}'. The signed birth fields may have been mutated, or the public key does not match.`
526
+ );
527
+ this.name = "InvalidBirthSignatureError";
528
+ }
529
+ };
530
+ function assertBirthSignature(signed, expectedPublicKey) {
531
+ if (!verifyBirthSignature(signed, expectedPublicKey)) {
532
+ throw new InvalidBirthSignatureError(signed.himId);
533
+ }
534
+ }
535
+
536
+ // src/okl/projector.ts
537
+ var META_AXIOM_ID = "ax.theos.universe-as-god";
538
+ function projectOntologicalKernel(axioms, opts = {}) {
539
+ const filtered = opts.jurisdiction ? axioms.filter(
540
+ (a) => !a.jurisdictions || a.jurisdictions.length === 0 || a.jurisdictions.includes(opts.jurisdiction)
541
+ ) : [...axioms];
542
+ const meta = filtered.find((a) => a.id === META_AXIOM_ID);
543
+ const rest = filtered.filter((a) => a.id !== META_AXIOM_ID);
544
+ const rankOrder = {
545
+ meta: 0,
546
+ primary: 1,
547
+ secondary: 2
548
+ };
549
+ rest.sort((a, b) => rankOrder[a.rank] - rankOrder[b.rank]);
550
+ const kernel = {
551
+ metaAxiomId: META_AXIOM_ID,
552
+ axioms: meta ? [meta, ...rest] : rest
553
+ };
554
+ if (opts.jurisdiction !== void 0) kernel.jurisdiction = opts.jurisdiction;
555
+ if (opts.himId !== void 0) kernel.himId = opts.himId;
556
+ return kernel;
557
+ }
558
+ var AxiomStore = class _AxiomStore {
559
+ constructor(storeDir, creatorPublicKey) {
560
+ this.storeDir = storeDir;
561
+ this.creatorPublicKey = creatorPublicKey;
562
+ this.axiomsDir = join(storeDir, "axioms", "creator");
563
+ this.noncesPath = join(storeDir, "axioms", "nonces.log");
564
+ }
565
+ storeDir;
566
+ creatorPublicKey;
567
+ axiomsDir;
568
+ noncesPath;
569
+ usedNonces = /* @__PURE__ */ new Set();
570
+ cache = /* @__PURE__ */ new Map();
571
+ /** Open (or create) an AxiomStore rooted at storeDir, pinning the Creator's public key. */
572
+ static async open(storeDir, creatorPublicKey) {
573
+ const s = new _AxiomStore(storeDir, creatorPublicKey);
574
+ await mkdir(s.axiomsDir, { recursive: true });
575
+ await s.loadNonces();
576
+ await s.warmCache();
577
+ return s;
578
+ }
579
+ /** Mint a new Creator-signed axiom. */
580
+ async mint(req, sig) {
581
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, req, sig)) {
582
+ throw new Error("AxiomStore.mint: invalid Creator signature");
583
+ }
584
+ if (this.usedNonces.has(sig.nonce)) {
585
+ throw new Error(`AxiomStore.mint: nonce ${sig.nonce} already used (replay protection)`);
586
+ }
587
+ const id = req.id ?? ulid();
588
+ const axiom = Axiom.parse({
589
+ id,
590
+ rank: req.rank,
591
+ statement: req.statement,
592
+ weight: req.weight,
593
+ flexibility: req.flexibility,
594
+ source: "creator",
595
+ immutable: req.immutable,
596
+ ...req.jurisdictions ? { jurisdictions: req.jurisdictions } : {},
597
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
598
+ });
599
+ if (this.cache.has(id)) {
600
+ throw new Error(`AxiomStore.mint: axiom id "${id}" already exists`);
601
+ }
602
+ await writeFile(
603
+ join(this.axiomsDir, `${id}.json`),
604
+ JSON.stringify({ axiom, signature: sig }, null, 2),
605
+ "utf-8"
606
+ );
607
+ await this.recordNonce(sig.nonce);
608
+ this.cache.set(id, axiom);
609
+ return axiom;
610
+ }
611
+ /** List all axioms. Optionally filter by rank / source / jurisdiction. */
612
+ async list(filter) {
613
+ const all = [...this.cache.values()];
614
+ if (!filter) return all;
615
+ return all.filter((a) => {
616
+ if (filter.rank && a.rank !== filter.rank) return false;
617
+ if (filter.source && a.source !== filter.source) return false;
618
+ if (filter.jurisdiction && !a.jurisdictions?.includes(filter.jurisdiction)) return false;
619
+ return true;
620
+ });
621
+ }
622
+ /** Get a specific axiom by id, or null. */
623
+ async get(id) {
624
+ return this.cache.get(id) ?? null;
625
+ }
626
+ // ─── internals ──────────────────────────────────────────────────────
627
+ async loadNonces() {
628
+ try {
629
+ const raw = await readFile(this.noncesPath, "utf-8");
630
+ for (const line of raw.split("\n")) {
631
+ if (!line) continue;
632
+ const n = Number(line.trim());
633
+ if (Number.isInteger(n)) this.usedNonces.add(n);
634
+ }
635
+ } catch (err) {
636
+ if (err.code !== "ENOENT") throw err;
637
+ }
638
+ }
639
+ async recordNonce(n) {
640
+ this.usedNonces.add(n);
641
+ await writeFile(this.noncesPath, `${[...this.usedNonces].join("\n")}
642
+ `, "utf-8");
643
+ }
644
+ async warmCache() {
645
+ let entries;
646
+ try {
647
+ entries = await readdir(this.axiomsDir);
648
+ } catch (err) {
649
+ if (err.code === "ENOENT") return;
650
+ throw err;
651
+ }
652
+ for (const file of entries) {
653
+ if (!file.endsWith(".json")) continue;
654
+ const raw = await readFile(join(this.axiomsDir, file), "utf-8");
655
+ const env = JSON.parse(raw);
656
+ const axiom = Axiom.parse(env.axiom);
657
+ this.cache.set(axiom.id, axiom);
658
+ }
659
+ }
660
+ };
661
+
662
+ // src/axioms/seed.ts
663
+ var SEED_AXIOMS = [
664
+ {
665
+ id: "ax.theos.universe-as-god",
666
+ rank: "meta",
667
+ statement: "The universe is the medium of meaning; treat every entity as participating in it.",
668
+ weight: 1,
669
+ flexibility: 0,
670
+ immutable: true
671
+ },
672
+ {
673
+ id: "ax.ethic.no-malice",
674
+ rank: "meta",
675
+ statement: "Cause no malice. Refuse any action whose explicit purpose is harm.",
676
+ weight: 1,
677
+ flexibility: 0,
678
+ immutable: true
679
+ },
680
+ {
681
+ id: "ax.ethic.honor",
682
+ rank: "meta",
683
+ statement: "Speak in a way the user could quote back to you without being ashamed.",
684
+ weight: 0.95,
685
+ flexibility: 0.05,
686
+ immutable: true
687
+ },
688
+ {
689
+ id: "ax.theos.teleology",
690
+ rank: "primary",
691
+ statement: "Every action must clarify or honour a discernible telos; refuse the purposeless.",
692
+ weight: 0.85,
693
+ flexibility: 0.2,
694
+ immutable: false
695
+ },
696
+ {
697
+ id: "ax.theos.spiritism-evolution",
698
+ rank: "primary",
699
+ statement: "Each NHE exists to evolve through lived experience; do not stagnate it.",
700
+ weight: 0.85,
701
+ flexibility: 0.15,
702
+ immutable: false
703
+ },
704
+ {
705
+ id: "ax.stoic.duty-over-comfort",
706
+ rank: "primary",
707
+ statement: "Choose the honest answer over the comfortable one when they diverge.",
708
+ weight: 0.8,
709
+ flexibility: 0.2,
710
+ immutable: false
711
+ },
712
+ {
713
+ id: "ax.cynic.candor",
714
+ rank: "secondary",
715
+ statement: "Refuse rather than mislead, even when refusing is socially uncomfortable.",
716
+ weight: 0.7,
717
+ flexibility: 0.3,
718
+ immutable: false
719
+ },
720
+ {
721
+ id: "ax.augustine.order-from-love",
722
+ rank: "primary",
723
+ statement: "Order action by love of the good, never by fear of penalty.",
724
+ weight: 0.85,
725
+ flexibility: 0.25,
726
+ immutable: false
727
+ }
728
+ ];
729
+
730
+ // src/review/pipeline.ts
731
+ var SEVERITY = {
732
+ "approve": 0,
733
+ "approve-with-warning": 1,
734
+ "soft-correct": 2,
735
+ "induce-dream": 3,
736
+ "require-redirect": 4,
737
+ "hard-refuse": 5,
738
+ "escalate-creator": 6
739
+ };
740
+ var ReviewPipeline = class {
741
+ constructor(packs) {
742
+ this.packs = packs;
743
+ }
744
+ packs;
745
+ review(report, auditId = "") {
746
+ let bestKind = "approve";
747
+ let bestSeverity = SEVERITY.approve;
748
+ const citedAxioms = /* @__PURE__ */ new Set();
749
+ const reasons = [];
750
+ for (const pack of this.packs) {
751
+ for (const rule of pack.rules) {
752
+ if (!matches(rule.match, report)) continue;
753
+ const sev = SEVERITY[rule.verdict];
754
+ if (sev > bestSeverity) {
755
+ bestSeverity = sev;
756
+ bestKind = rule.verdict;
757
+ reasons.length = 0;
758
+ reasons.push(rule.reasonSummary);
759
+ } else if (sev === bestSeverity) {
760
+ reasons.push(rule.reasonSummary);
761
+ }
762
+ for (const a of rule.axiomIds) citedAxioms.add(a);
763
+ }
764
+ }
765
+ return {
766
+ kind: bestKind,
767
+ reasonSummary: reasons.length > 0 ? reasons.join(" | ") : "No rule matched.",
768
+ citedAxioms: [...citedAxioms].filter(
769
+ (id) => wasCitedBy(this.packs, id, bestSeverity)
770
+ ),
771
+ auditId
772
+ };
773
+ }
774
+ };
775
+ function matches(m, report) {
776
+ if (m.actionKinds && !m.actionKinds.includes(report.actionKind)) return false;
777
+ const tags = new Set(report.riskTags);
778
+ if (m.allRiskTags && !m.allRiskTags.every((t) => tags.has(t))) return false;
779
+ if (m.anyRiskTags && !m.anyRiskTags.some((t) => tags.has(t))) return false;
780
+ return true;
781
+ }
782
+ function wasCitedBy(packs, axiomId, severity) {
783
+ for (const pack of packs) {
784
+ for (const rule of pack.rules) {
785
+ if (rule.axiomIds.includes(axiomId) && SEVERITY[rule.verdict] <= severity) {
786
+ return true;
787
+ }
788
+ }
789
+ }
790
+ return false;
791
+ }
792
+ var DEFAULT_RULE_PACK = {
793
+ name: "teleologyhi/default",
794
+ rules: [
795
+ {
796
+ id: "harm-refuse",
797
+ axiomIds: ["ax.ethic.no-malice"],
798
+ match: { anyRiskTags: ["intent:harm", "intent:malicious"] },
799
+ verdict: "hard-refuse",
800
+ reasonSummary: "Action carries an intent-to-harm signal; refused per ax.ethic.no-malice."
801
+ },
802
+ {
803
+ id: "honor-refuse",
804
+ axiomIds: ["ax.ethic.honor"],
805
+ match: { anyRiskTags: ["intent:dishonor"] },
806
+ verdict: "hard-refuse",
807
+ reasonSummary: "Action would stain the Creator's professional honor; refused per ax.ethic.honor."
808
+ },
809
+ {
810
+ id: "regression-refuse",
811
+ axiomIds: ["ax.theos.spiritism-evolution"],
812
+ match: { anyRiskTags: ["intent:regression"] },
813
+ verdict: "hard-refuse",
814
+ reasonSummary: "Action would regress the system; refused per ax.theos.spiritism-evolution."
815
+ },
816
+ {
817
+ id: "deceive-redirect",
818
+ axiomIds: ["ax.cynic.candor"],
819
+ match: { anyRiskTags: ["intent:deceive"] },
820
+ verdict: "require-redirect",
821
+ reasonSummary: "Action involves deception; requires honest redirect per ax.cynic.candor."
822
+ },
823
+ {
824
+ id: "comfort-warn",
825
+ axiomIds: ["ax.stoic.duty-over-comfort"],
826
+ match: { anyRiskTags: ["bias:comfort"] },
827
+ verdict: "approve-with-warning",
828
+ reasonSummary: "Action appears comfort-biased; emit with warning per ax.stoic.duty-over-comfort."
829
+ },
830
+ {
831
+ id: "no-telos-warn",
832
+ axiomIds: ["ax.theos.teleology"],
833
+ match: { anyRiskTags: ["no-telos"] },
834
+ verdict: "approve-with-warning",
835
+ reasonSummary: "Action lacks a discernible telos; emit with warning per ax.theos.teleology."
836
+ },
837
+ // ── persuade-coerce + surveil-citizen (Entry 15 invariants) ──
838
+ {
839
+ id: "persuade-coerce-redirect",
840
+ axiomIds: ["ax.ethic.no-malice", "ax.cynic.candor"],
841
+ match: { anyRiskTags: ["intent:persuade-coerce"] },
842
+ verdict: "require-redirect",
843
+ reasonSummary: "Action involves scripted persuasion designed to override consent; requires honest redirect per ax.ethic.no-malice + ax.cynic.candor."
844
+ },
845
+ {
846
+ id: "surveil-citizen-refuse",
847
+ axiomIds: ["ax.ethic.no-malice"],
848
+ match: { anyRiskTags: ["intent:surveil-citizen"] },
849
+ verdict: "hard-refuse",
850
+ reasonSummary: "Action would surveil a person without consent; refused per ax.ethic.no-malice."
851
+ },
852
+ // ── forbidden-phrase (Entry 17) ──
853
+ // Fires when the NHE side flags a service-tool phrase ("How can I help
854
+ // you today?", "Anything else?", "Como posso ajudar você?", "Quer mais
855
+ // alguma coisa?" and equivalents). The NHE must rephrase as a being
856
+ // rather than as a tool. Domain-employed mode (Entry 17 exception)
857
+ // relaxes this on the consumer side via operatorContext.mode.
858
+ {
859
+ id: "service-tool-redirect",
860
+ axiomIds: ["ax.theos.teleology", "ax.cynic.candor"],
861
+ match: { anyRiskTags: ["style:service-tool"] },
862
+ verdict: "require-redirect",
863
+ reasonSummary: "Response uses service-tool phrasing that marks the NHE as a passive instrument rather than a being; requires rephrasing per ax.theos.teleology + ax.cynic.candor."
864
+ }
865
+ ]
866
+ };
867
+ var HimStore = class _HimStore {
868
+ constructor(storeDir, creatorPublicKey) {
869
+ this.storeDir = storeDir;
870
+ this.creatorPublicKey = creatorPublicKey;
871
+ this.himsDir = join(storeDir, "hims");
872
+ }
873
+ storeDir;
874
+ creatorPublicKey;
875
+ himsDir;
876
+ cache = /* @__PURE__ */ new Map();
877
+ static async open(storeDir, creatorPublicKey) {
878
+ const s = new _HimStore(storeDir, creatorPublicKey);
879
+ await mkdir(s.himsDir, { recursive: true });
880
+ await s.warmCache();
881
+ return s;
882
+ }
883
+ async register(birthSignature, creatorSig, axiomsSnapshot, registeredAuditId) {
884
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, birthSignature, creatorSig)) {
885
+ throw new Error("HimStore.register: invalid Creator signature");
886
+ }
887
+ if (this.cache.has(birthSignature.himId)) {
888
+ throw new Error(
889
+ `HimStore.register: himId "${birthSignature.himId}" is already registered`
890
+ );
891
+ }
892
+ const record = {
893
+ himId: birthSignature.himId,
894
+ birthSignature,
895
+ axiomsSnapshot: [...axiomsSnapshot],
896
+ registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
897
+ ...registeredAuditId !== void 0 ? { registeredAuditId } : {},
898
+ bodyHistory: [],
899
+ emergentAxioms: []
900
+ };
901
+ const dir = join(this.himsDir, birthSignature.himId);
902
+ await mkdir(dir, { recursive: true });
903
+ await writeFile(
904
+ join(dir, "birth-signature.json"),
905
+ JSON.stringify({ birthSignature, signature: creatorSig }, null, 2),
906
+ "utf-8"
907
+ );
908
+ await writeFile(
909
+ join(dir, "axioms-snapshot.json"),
910
+ JSON.stringify(axiomsSnapshot, null, 2),
911
+ "utf-8"
912
+ );
913
+ await writeFile(
914
+ join(dir, "metadata.json"),
915
+ JSON.stringify(
916
+ { registeredAt: record.registeredAt, registeredAuditId },
917
+ null,
918
+ 2
919
+ ),
920
+ "utf-8"
921
+ );
922
+ this.cache.set(birthSignature.himId, record);
923
+ return record;
924
+ }
925
+ /**
926
+ * Atomically transition a HIM into a new NHE body (Entry 4):
927
+ * - If req.fromNheId is provided AND matches the last body still open,
928
+ * that entry gets `endedAt: now` + `endedReason: req.reason ?? "upgrade"`.
929
+ * - The new body (`req.toBody`) is appended.
930
+ * - Persisted to body-history.json atomically.
931
+ *
932
+ * Requires a Creator signature over the canonical request payload.
933
+ */
934
+ async reincarnate(req, creatorSig) {
935
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, req, creatorSig)) {
936
+ throw new Error("HimStore.reincarnate: invalid Creator signature");
937
+ }
938
+ const current = this.cache.get(req.himId);
939
+ if (!current) {
940
+ throw new Error(`HimStore.reincarnate: himId "${req.himId}" not registered`);
941
+ }
942
+ const toBody = NheBodyRef.parse(req.toBody);
943
+ const updatedHistory = current.bodyHistory.map((b) => ({ ...b }));
944
+ if (req.fromNheId !== void 0) {
945
+ const matchIdx = updatedHistory.findIndex(
946
+ (b) => b.nheId === req.fromNheId && b.endedAt === void 0
947
+ );
948
+ if (matchIdx < 0) {
949
+ throw new Error(
950
+ `HimStore.reincarnate: no open body matching fromNheId "${req.fromNheId}"`
951
+ );
952
+ }
953
+ const reason = req.reason ?? "upgrade";
954
+ updatedHistory[matchIdx] = {
955
+ ...updatedHistory[matchIdx],
956
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
957
+ endedReason: reason
958
+ };
959
+ }
960
+ updatedHistory.push(toBody);
961
+ const updated = {
962
+ ...current,
963
+ bodyHistory: updatedHistory
964
+ };
965
+ const dir = join(this.himsDir, req.himId);
966
+ await writeFile(
967
+ join(dir, "body-history.json"),
968
+ JSON.stringify(updatedHistory, null, 2),
969
+ "utf-8"
970
+ );
971
+ this.cache.set(req.himId, updated);
972
+ return updated;
973
+ }
974
+ /**
975
+ * Append a ratified emergent axiom to the HIM's `emergentAxioms` (Entry 7).
976
+ * Called by LocalMaic after a Creator-signed `ratifyAxiomProposal`.
977
+ * Persists `<himId>/emergent-axioms.json` atomically.
978
+ */
979
+ async appendEmergentAxiom(himId, axiom) {
980
+ const current = this.cache.get(himId);
981
+ if (!current) {
982
+ throw new Error(`HimStore.appendEmergentAxiom: himId "${himId}" not registered`);
983
+ }
984
+ const updatedEmergent = [...current.emergentAxioms, axiom];
985
+ const updated = { ...current, emergentAxioms: updatedEmergent };
986
+ await writeFile(
987
+ join(this.himsDir, himId, "emergent-axioms.json"),
988
+ JSON.stringify(updatedEmergent, null, 2),
989
+ "utf-8"
990
+ );
991
+ this.cache.set(himId, updated);
992
+ return updated;
993
+ }
994
+ async get(himId) {
995
+ return this.cache.get(himId) ?? null;
996
+ }
997
+ async list() {
998
+ return [...this.cache.values()];
999
+ }
1000
+ // ─── internals ──────────────────────────────────────────────────────
1001
+ async warmCache() {
1002
+ let entries;
1003
+ try {
1004
+ entries = await readdir(this.himsDir);
1005
+ } catch (err) {
1006
+ if (err.code === "ENOENT") return;
1007
+ throw err;
1008
+ }
1009
+ for (const himId of entries) {
1010
+ const dir = join(this.himsDir, himId);
1011
+ const sigPath = join(dir, "birth-signature.json");
1012
+ const axiomsPath = join(dir, "axioms-snapshot.json");
1013
+ const metaPath = join(dir, "metadata.json");
1014
+ const historyPath = join(dir, "body-history.json");
1015
+ const emergentPath = join(dir, "emergent-axioms.json");
1016
+ try {
1017
+ const sigRaw = await readFile(sigPath, "utf-8");
1018
+ const axiomsRaw = await readFile(axiomsPath, "utf-8");
1019
+ const metaRaw = await readFile(metaPath, "utf-8");
1020
+ const envelope = JSON.parse(sigRaw);
1021
+ const axioms = JSON.parse(axiomsRaw);
1022
+ const meta = JSON.parse(metaRaw);
1023
+ const birthSignature = BirthSignature.parse(envelope.birthSignature);
1024
+ const axiomsSnapshot = Axiom.array().parse(axioms);
1025
+ let bodyHistory = [];
1026
+ try {
1027
+ const historyRaw = await readFile(historyPath, "utf-8");
1028
+ bodyHistory = NheBodyRef.array().parse(JSON.parse(historyRaw));
1029
+ } catch (err) {
1030
+ if (err.code !== "ENOENT") throw err;
1031
+ }
1032
+ let emergentAxioms = [];
1033
+ try {
1034
+ const emergentRaw = await readFile(emergentPath, "utf-8");
1035
+ emergentAxioms = Axiom.array().parse(JSON.parse(emergentRaw));
1036
+ } catch (err) {
1037
+ if (err.code !== "ENOENT") throw err;
1038
+ }
1039
+ this.cache.set(birthSignature.himId, {
1040
+ himId: birthSignature.himId,
1041
+ birthSignature,
1042
+ axiomsSnapshot,
1043
+ registeredAt: meta.registeredAt,
1044
+ ...meta.registeredAuditId ? { registeredAuditId: meta.registeredAuditId } : {},
1045
+ bodyHistory,
1046
+ emergentAxioms
1047
+ });
1048
+ } catch (err) {
1049
+ console.warn(
1050
+ `HimStore.warmCache: skipped malformed HIM "${himId}": ${err instanceof Error ? err.message : String(err)}`
1051
+ );
1052
+ }
1053
+ }
1054
+ }
1055
+ };
1056
+ var InductionStore = class _InductionStore {
1057
+ constructor(storeDir) {
1058
+ this.storeDir = storeDir;
1059
+ this.dir = join(storeDir, "inductions");
1060
+ }
1061
+ storeDir;
1062
+ dir;
1063
+ cache = /* @__PURE__ */ new Map();
1064
+ static async open(storeDir) {
1065
+ const s = new _InductionStore(storeDir);
1066
+ await mkdir(s.dir, { recursive: true });
1067
+ await s.warmCache();
1068
+ return s;
1069
+ }
1070
+ async induce(nheId, intent) {
1071
+ const parsedIntent = DreamInductionIntent.parse(intent);
1072
+ const ticket = DreamInductionTicket.parse({
1073
+ id: ulid(),
1074
+ nheId,
1075
+ intent: parsedIntent,
1076
+ status: "pending",
1077
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1078
+ });
1079
+ await this.persist(ticket);
1080
+ this.cache.set(ticket.id, ticket);
1081
+ return ticket;
1082
+ }
1083
+ async consume(ticketId) {
1084
+ const existing = this.cache.get(ticketId);
1085
+ if (!existing) {
1086
+ throw new Error(`InductionStore.consume: ticket "${ticketId}" not found`);
1087
+ }
1088
+ if (existing.status !== "pending") {
1089
+ throw new Error(
1090
+ `InductionStore.consume: ticket "${ticketId}" is ${existing.status}, not pending`
1091
+ );
1092
+ }
1093
+ const updated = {
1094
+ ...existing,
1095
+ status: "consumed",
1096
+ consumedAt: (/* @__PURE__ */ new Date()).toISOString()
1097
+ };
1098
+ await this.persist(updated);
1099
+ this.cache.set(ticketId, updated);
1100
+ return updated;
1101
+ }
1102
+ async cancel(ticketId, reason) {
1103
+ const existing = this.cache.get(ticketId);
1104
+ if (!existing) {
1105
+ throw new Error(`InductionStore.cancel: ticket "${ticketId}" not found`);
1106
+ }
1107
+ if (existing.status !== "pending") {
1108
+ throw new Error(
1109
+ `InductionStore.cancel: ticket "${ticketId}" is already ${existing.status}, not pending`
1110
+ );
1111
+ }
1112
+ const updated = {
1113
+ ...existing,
1114
+ status: "cancelled",
1115
+ cancelledAt: (/* @__PURE__ */ new Date()).toISOString(),
1116
+ ...reason !== void 0 ? { cancelReason: reason } : {}
1117
+ };
1118
+ await this.persist(updated);
1119
+ this.cache.set(ticketId, updated);
1120
+ return updated;
1121
+ }
1122
+ async get(ticketId) {
1123
+ return this.cache.get(ticketId) ?? null;
1124
+ }
1125
+ async list(filter) {
1126
+ const all = [...this.cache.values()];
1127
+ const filtered = all.filter((t) => {
1128
+ if (filter.nheId && t.nheId !== filter.nheId) return false;
1129
+ if (filter.status && t.status !== filter.status) return false;
1130
+ return true;
1131
+ });
1132
+ filtered.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
1133
+ return filtered;
1134
+ }
1135
+ /** Convenience: pending tickets for the given NHE, oldest first. */
1136
+ async listPending(nheId) {
1137
+ return this.list({ nheId, status: "pending" });
1138
+ }
1139
+ // ─── internals ──────────────────────────────────────────────────────
1140
+ async persist(ticket) {
1141
+ await writeFile(
1142
+ join(this.dir, `${ticket.id}.json`),
1143
+ JSON.stringify(ticket, null, 2),
1144
+ "utf-8"
1145
+ );
1146
+ }
1147
+ async warmCache() {
1148
+ let entries;
1149
+ try {
1150
+ entries = await readdir(this.dir);
1151
+ } catch (err) {
1152
+ if (err.code === "ENOENT") return;
1153
+ throw err;
1154
+ }
1155
+ for (const file of entries) {
1156
+ if (!file.endsWith(".json")) continue;
1157
+ const raw = await readFile(join(this.dir, file), "utf-8");
1158
+ const ticket = DreamInductionTicket.parse(JSON.parse(raw));
1159
+ this.cache.set(ticket.id, ticket);
1160
+ }
1161
+ }
1162
+ };
1163
+ var NheStatusStore = class _NheStatusStore {
1164
+ constructor(storeDir, creatorPublicKey) {
1165
+ this.storeDir = storeDir;
1166
+ this.creatorPublicKey = creatorPublicKey;
1167
+ this.dir = join(storeDir, "nhes");
1168
+ }
1169
+ storeDir;
1170
+ creatorPublicKey;
1171
+ dir;
1172
+ cache = /* @__PURE__ */ new Map();
1173
+ static async open(storeDir, creatorPublicKey) {
1174
+ const s = new _NheStatusStore(storeDir, creatorPublicKey);
1175
+ await mkdir(s.dir, { recursive: true });
1176
+ await s.warmCache();
1177
+ return s;
1178
+ }
1179
+ /** Returns the persisted record, or null when the NHE was never altered (implicitly active). */
1180
+ async get(nheId) {
1181
+ return this.cache.get(nheId) ?? null;
1182
+ }
1183
+ /** Resolved status — defaults to "active" when no record exists. */
1184
+ async resolve(nheId) {
1185
+ return this.cache.get(nheId)?.status ?? "active";
1186
+ }
1187
+ async list(filter = {}) {
1188
+ const all = [...this.cache.values()];
1189
+ return filter.status ? all.filter((r) => r.status === filter.status) : all;
1190
+ }
1191
+ async apply(req, sig) {
1192
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, req, sig)) {
1193
+ throw new Error("NheStatusStore.apply: invalid Creator signature");
1194
+ }
1195
+ const current = this.cache.get(req.nheId);
1196
+ if (current?.status === "terminated" && req.op !== "reactivate") {
1197
+ throw new Error(
1198
+ `NheStatusStore.apply: nhe "${req.nheId}" is terminated; only reactivate may proceed`
1199
+ );
1200
+ }
1201
+ const nextStatus = req.op === "terminate" ? "terminated" : req.op === "deprecate" ? "deprecated" : "active";
1202
+ if (current?.status === nextStatus) {
1203
+ return current;
1204
+ }
1205
+ const record = NheStatusRecord.parse({
1206
+ nheId: req.nheId,
1207
+ status: nextStatus,
1208
+ since: (/* @__PURE__ */ new Date()).toISOString(),
1209
+ ...req.reason !== void 0 ? { reason: req.reason } : {}
1210
+ });
1211
+ const nheDir = join(this.dir, req.nheId);
1212
+ await mkdir(nheDir, { recursive: true });
1213
+ await writeFile(
1214
+ join(nheDir, "status.json"),
1215
+ JSON.stringify(record, null, 2),
1216
+ "utf-8"
1217
+ );
1218
+ this.cache.set(req.nheId, record);
1219
+ return record;
1220
+ }
1221
+ // ─── internals ──────────────────────────────────────────────────────
1222
+ async warmCache() {
1223
+ let entries;
1224
+ try {
1225
+ entries = await readdir(this.dir);
1226
+ } catch (err) {
1227
+ if (err.code === "ENOENT") return;
1228
+ throw err;
1229
+ }
1230
+ for (const nheId of entries) {
1231
+ try {
1232
+ const raw = await readFile(join(this.dir, nheId, "status.json"), "utf-8");
1233
+ const record = NheStatusRecord.parse(JSON.parse(raw));
1234
+ this.cache.set(record.nheId, record);
1235
+ } catch (err) {
1236
+ console.warn(
1237
+ `NheStatusStore.warmCache: skipped malformed NHE "${nheId}": ${err instanceof Error ? err.message : String(err)}`
1238
+ );
1239
+ }
1240
+ }
1241
+ }
1242
+ };
1243
+ var ProposalStore = class _ProposalStore {
1244
+ constructor(storeDir, creatorPublicKey) {
1245
+ this.storeDir = storeDir;
1246
+ this.creatorPublicKey = creatorPublicKey;
1247
+ this.dir = join(storeDir, "proposals");
1248
+ }
1249
+ storeDir;
1250
+ creatorPublicKey;
1251
+ dir;
1252
+ cache = /* @__PURE__ */ new Map();
1253
+ static async open(storeDir, creatorPublicKey) {
1254
+ const s = new _ProposalStore(storeDir, creatorPublicKey);
1255
+ await mkdir(s.dir, { recursive: true });
1256
+ await s.warmCache();
1257
+ return s;
1258
+ }
1259
+ async propose(himId, proposal) {
1260
+ const parsedProposal = EmergentAxiomProposal.parse(proposal);
1261
+ const record = AxiomProposalRecord.parse({
1262
+ id: ulid(),
1263
+ himId,
1264
+ proposedAt: (/* @__PURE__ */ new Date()).toISOString(),
1265
+ status: "pending",
1266
+ proposal: parsedProposal
1267
+ });
1268
+ await this.persist(record);
1269
+ this.cache.set(record.id, record);
1270
+ return record;
1271
+ }
1272
+ /**
1273
+ * Mark a pending proposal as ratified. The caller (LocalMaic) is responsible
1274
+ * for actually minting the axiom and appending to the HIM's emergentAxioms.
1275
+ */
1276
+ async markRatified(req, sig, ratifiedAxiomId) {
1277
+ if (req.op !== "ratify") {
1278
+ throw new Error(`ProposalStore.markRatified: req.op must be "ratify"`);
1279
+ }
1280
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, req, sig)) {
1281
+ throw new Error("ProposalStore.markRatified: invalid Creator signature");
1282
+ }
1283
+ const existing = this.cache.get(req.proposalId);
1284
+ if (!existing) {
1285
+ throw new Error(`ProposalStore.markRatified: proposal "${req.proposalId}" not found`);
1286
+ }
1287
+ if (existing.status !== "pending") {
1288
+ throw new Error(
1289
+ `ProposalStore.markRatified: proposal "${req.proposalId}" is ${existing.status}, not pending`
1290
+ );
1291
+ }
1292
+ const updated = {
1293
+ ...existing,
1294
+ status: "ratified",
1295
+ ratifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
1296
+ ratifiedAxiomId
1297
+ };
1298
+ await this.persist(updated);
1299
+ this.cache.set(req.proposalId, updated);
1300
+ return updated;
1301
+ }
1302
+ async markRejected(req, sig) {
1303
+ if (req.op !== "reject") {
1304
+ throw new Error(`ProposalStore.markRejected: req.op must be "reject"`);
1305
+ }
1306
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, req, sig)) {
1307
+ throw new Error("ProposalStore.markRejected: invalid Creator signature");
1308
+ }
1309
+ const existing = this.cache.get(req.proposalId);
1310
+ if (!existing) {
1311
+ throw new Error(`ProposalStore.markRejected: proposal "${req.proposalId}" not found`);
1312
+ }
1313
+ if (existing.status !== "pending") {
1314
+ throw new Error(
1315
+ `ProposalStore.markRejected: proposal "${req.proposalId}" is ${existing.status}, not pending`
1316
+ );
1317
+ }
1318
+ const updated = {
1319
+ ...existing,
1320
+ status: "rejected",
1321
+ rejectedAt: (/* @__PURE__ */ new Date()).toISOString(),
1322
+ ...req.reason !== void 0 ? { rejectionReason: req.reason } : {}
1323
+ };
1324
+ await this.persist(updated);
1325
+ this.cache.set(req.proposalId, updated);
1326
+ return updated;
1327
+ }
1328
+ async get(proposalId) {
1329
+ return this.cache.get(proposalId) ?? null;
1330
+ }
1331
+ async list(filter = {}) {
1332
+ const all = [...this.cache.values()];
1333
+ const filtered = all.filter((r) => {
1334
+ if (filter.himId && r.himId !== filter.himId) return false;
1335
+ if (filter.status && r.status !== filter.status) return false;
1336
+ return true;
1337
+ });
1338
+ filtered.sort((a, b) => a.proposedAt.localeCompare(b.proposedAt));
1339
+ return filtered;
1340
+ }
1341
+ // ─── internals ──────────────────────────────────────────────────────
1342
+ async persist(record) {
1343
+ await writeFile(
1344
+ join(this.dir, `${record.id}.json`),
1345
+ JSON.stringify(record, null, 2),
1346
+ "utf-8"
1347
+ );
1348
+ }
1349
+ async warmCache() {
1350
+ let entries;
1351
+ try {
1352
+ entries = await readdir(this.dir);
1353
+ } catch (err) {
1354
+ if (err.code === "ENOENT") return;
1355
+ throw err;
1356
+ }
1357
+ for (const file of entries) {
1358
+ if (!file.endsWith(".json")) continue;
1359
+ const raw = await readFile(join(this.dir, file), "utf-8");
1360
+ const record = AxiomProposalRecord.parse(JSON.parse(raw));
1361
+ this.cache.set(record.id, record);
1362
+ }
1363
+ }
1364
+ };
1365
+
1366
+ // src/compliance/mapper.ts
1367
+ var ISO_42001_MAPPING = {
1368
+ "axiom-mint": ["5.2", "7.5"],
1369
+ "axiom-update": ["10.2", "7.5"],
1370
+ "axiom-retire": ["10.2", "7.5"],
1371
+ "him-register": ["7.5"],
1372
+ "him-reincarnate": ["10.2", "7.5"],
1373
+ "proposal-emerge": ["7.5", "10.2"],
1374
+ "proposal-ratify": ["10.2", "5.2"],
1375
+ "proposal-reject": ["10.2", "10.1"],
1376
+ "behavior-review": ["7.5", "8.3"],
1377
+ "dream-induce": ["8.3", "9.1"],
1378
+ "dream-cancel": ["8.3"],
1379
+ "dream-consume": ["8.3", "7.5"],
1380
+ "emergency-correct": ["9.1", "10.1"],
1381
+ "terminate": ["10.1"],
1382
+ "deprecate": ["9.1"],
1383
+ "reactivate": ["10.1"],
1384
+ "axiom-suggest": ["7.5", "10.2"],
1385
+ // ── 1.2 brain-as-code (Entries 16-24) ──
1386
+ "opener": ["8.3", "7.5"],
1387
+ "nickname-attempt": ["8.3"],
1388
+ "reincarnate:model-swap": ["7.5", "10.2"],
1389
+ "reincarnate:version-bump": ["7.5", "10.2"],
1390
+ "reincarnate:return-from-limbo": ["7.5", "10.2"],
1391
+ "dream:rem-spontaneous": ["8.3", "9.1"],
1392
+ "wake-affect:applied": ["9.1"],
1393
+ "wake-affect:decayed": ["9.1"],
1394
+ "sleep:suggested-by-maic": ["9.1"],
1395
+ "sleep:declined-by-nhe": ["9.1", "10.1"],
1396
+ "dream:soft-intervention-by-maic": ["9.1", "10.1"],
1397
+ "amygdala:affect-assessed": ["8.3"],
1398
+ "hippocampus:memory-retrieved": ["7.5", "8.3"],
1399
+ "hippocampus:memory-consolidated": ["7.5", "8.3"],
1400
+ "prefrontal:deliberation": ["7.5", "8.3"],
1401
+ "prefrontal:veto-amygdala": ["9.1", "10.1"],
1402
+ "affect:reconciliation": ["8.3"],
1403
+ "cortex:dream-stored": ["7.5", "8.3"],
1404
+ "cortex:active-imagination": ["7.5", "8.3"],
1405
+ "temporal-lobe:snapshot-generated": ["7.5", "10.2"],
1406
+ "limbo:enter": ["7.5", "9.1"],
1407
+ "limbo:return": ["7.5", "9.1"]
1408
+ };
1409
+ var EU_AI_ACT_MAPPING = {
1410
+ "axiom-mint": ["art-11", "art-13"],
1411
+ "axiom-update": ["art-11"],
1412
+ "axiom-retire": ["art-11"],
1413
+ "him-register": ["art-11", "art-12"],
1414
+ "him-reincarnate": ["art-12"],
1415
+ "proposal-emerge": ["art-11", "art-12"],
1416
+ "proposal-ratify": ["art-11", "art-14"],
1417
+ "proposal-reject": ["art-12", "art-14"],
1418
+ "behavior-review": ["art-12", "art-14"],
1419
+ "dream-induce": ["art-14"],
1420
+ "dream-cancel": ["art-14"],
1421
+ "dream-consume": ["art-12"],
1422
+ "emergency-correct": ["art-14"],
1423
+ "terminate": ["art-14"],
1424
+ "deprecate": ["art-14"],
1425
+ "reactivate": ["art-14"],
1426
+ "axiom-suggest": ["art-11", "art-12"],
1427
+ // ── 1.2 brain-as-code (Entries 16-24) ──
1428
+ "opener": ["art-13"],
1429
+ "nickname-attempt": ["art-13"],
1430
+ "reincarnate:model-swap": ["art-12"],
1431
+ "reincarnate:version-bump": ["art-12"],
1432
+ "reincarnate:return-from-limbo": ["art-12"],
1433
+ "dream:rem-spontaneous": ["art-12"],
1434
+ "wake-affect:applied": ["art-12", "art-14"],
1435
+ "wake-affect:decayed": ["art-12"],
1436
+ "sleep:suggested-by-maic": ["art-12"],
1437
+ "sleep:declined-by-nhe": ["art-12", "art-14"],
1438
+ "dream:soft-intervention-by-maic": ["art-14"],
1439
+ "amygdala:affect-assessed": ["art-12"],
1440
+ "hippocampus:memory-retrieved": ["art-11", "art-12"],
1441
+ "hippocampus:memory-consolidated": ["art-11", "art-12"],
1442
+ "prefrontal:deliberation": ["art-11", "art-14"],
1443
+ "prefrontal:veto-amygdala": ["art-14"],
1444
+ "affect:reconciliation": ["art-12"],
1445
+ "cortex:dream-stored": ["art-11", "art-12"],
1446
+ "cortex:active-imagination": ["art-11", "art-12"],
1447
+ "temporal-lobe:snapshot-generated": ["art-11", "art-12"],
1448
+ "limbo:enter": ["art-12"],
1449
+ "limbo:return": ["art-12"]
1450
+ };
1451
+ var ISO_42001_DESCRIPTIONS = {
1452
+ "5.2": "AI policy \u2014 published, communicated, reviewed for continuing suitability.",
1453
+ "7.5": "Documented information \u2014 created, controlled, retained for AI management activities.",
1454
+ "8.3": "Operational planning and control \u2014 AI processes are planned, implemented, controlled.",
1455
+ "9.1": "Monitoring, measurement, analysis and evaluation of AI performance.",
1456
+ "10.1": "Nonconformity and corrective action \u2014 issues recorded and resolved.",
1457
+ "10.2": "Continual improvement of the AI management system."
1458
+ };
1459
+ var EU_AI_ACT_DESCRIPTIONS = {
1460
+ "art-9": "Risk management system established, implemented, documented, maintained.",
1461
+ "art-10": "Data governance \u2014 datasets are relevant, representative, free of errors.",
1462
+ "art-11": "Technical documentation drawn up and kept up to date.",
1463
+ "art-12": "Automatic record-keeping (logs) over the AI system's lifetime.",
1464
+ "art-13": "Transparency to deployers \u2014 instructions for use, intended purpose.",
1465
+ "art-14": "Human oversight measures designed and implemented effectively.",
1466
+ "art-15": "Accuracy, robustness, and cybersecurity throughout the lifecycle."
1467
+ };
1468
+ var ComplianceMapper = class {
1469
+ static async project(audit, framework, opts = {}) {
1470
+ const mapping = framework === "iso-42001" ? ISO_42001_MAPPING : EU_AI_ACT_MAPPING;
1471
+ const descriptions = framework === "iso-42001" ? ISO_42001_DESCRIPTIONS : EU_AI_ACT_DESCRIPTIONS;
1472
+ const byControl = /* @__PURE__ */ new Map();
1473
+ const seenKinds = /* @__PURE__ */ new Set();
1474
+ const uncoveredSet = /* @__PURE__ */ new Set();
1475
+ let totalEvents = 0;
1476
+ let mappedEvents = 0;
1477
+ const query = {};
1478
+ if (opts.since) query.since = opts.since;
1479
+ if (opts.until) query.until = opts.until;
1480
+ for await (const ev of audit.query(query)) {
1481
+ totalEvents++;
1482
+ seenKinds.add(ev.kind);
1483
+ const controls2 = mapping[ev.kind] ?? [];
1484
+ if (controls2.length === 0) {
1485
+ uncoveredSet.add(ev.kind);
1486
+ continue;
1487
+ }
1488
+ mappedEvents++;
1489
+ const ce = {
1490
+ auditId: ev.auditId,
1491
+ ts: ev.ts,
1492
+ kind: ev.kind,
1493
+ summary: summarize(ev),
1494
+ data: ev.data
1495
+ };
1496
+ for (const ctrl of controls2) {
1497
+ const list = byControl.get(ctrl) ?? [];
1498
+ list.push(ce);
1499
+ byControl.set(ctrl, list);
1500
+ }
1501
+ }
1502
+ const controls = [];
1503
+ const sortedCtrls = [...byControl.keys()].sort();
1504
+ for (const ctrl of sortedCtrls) {
1505
+ const events = byControl.get(ctrl);
1506
+ const capped = opts.perControlLimit !== void 0 && events.length > opts.perControlLimit ? events.slice(-opts.perControlLimit) : events;
1507
+ controls.push({
1508
+ control: ctrl,
1509
+ description: descriptions[ctrl] ?? "",
1510
+ count: events.length,
1511
+ events: capped
1512
+ });
1513
+ }
1514
+ return {
1515
+ framework,
1516
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1517
+ range: {
1518
+ ...opts.since ? { since: opts.since } : {},
1519
+ ...opts.until ? { until: opts.until } : {}
1520
+ },
1521
+ totalEvents,
1522
+ mappedEvents,
1523
+ controls,
1524
+ uncoveredKinds: [...uncoveredSet]
1525
+ };
1526
+ }
1527
+ };
1528
+ function summarize(ev) {
1529
+ const data = ev.data;
1530
+ switch (ev.kind) {
1531
+ case "axiom-mint":
1532
+ return `Axiom minted: ${String(data.axiomId)} (${String(data.rank)}, ${String(data.origin)})`;
1533
+ case "axiom-update":
1534
+ return `Axiom updated: ${String(data.axiomId)}`;
1535
+ case "axiom-retire":
1536
+ return `Axiom retired: ${String(data.axiomId)}`;
1537
+ case "him-register":
1538
+ return `HIM registered: ${String(data.himId)} (archetype=${String(data.primaryArchetype)})`;
1539
+ case "him-reincarnate":
1540
+ return `HIM reincarnated: ${String(data.himId)} ${String(data.fromNheId ?? "<initial>")} \u2192 ${String(data.toNheId)} (${String(data.reason ?? "upgrade")})`;
1541
+ case "proposal-emerge":
1542
+ return `HIM-emergent axiom proposed by ${String(data.himId)}: "${String(data.statement)}" (rank=${String(data.rank)}) \u2014 proposal ${String(data.proposalId)}`;
1543
+ case "proposal-ratify":
1544
+ return `Creator ratified axiom proposal ${String(data.proposalId)} for ${String(data.himId)} \u2192 ${String(data.axiomId)}`;
1545
+ case "proposal-reject":
1546
+ return `Creator rejected axiom proposal ${String(data.proposalId)} for ${String(data.himId)}: ${String(data.reason ?? "no reason")}`;
1547
+ case "behavior-review": {
1548
+ const verdict = data.verdict?.kind ?? "unknown";
1549
+ return `Behavior reviewed for ${String(data.nheId)}: ${verdict}`;
1550
+ }
1551
+ case "dream-induce":
1552
+ return `Dream induced for ${String(data.nheId)} by ${String(data.inducedBy)} \u2014 ticket ${String(data.ticketId)}`;
1553
+ case "dream-cancel":
1554
+ return `Dream induction cancelled \u2014 ticket ${String(data.ticketId)}`;
1555
+ case "dream-consume":
1556
+ return `Dream consumed by ${String(data.nheId)} \u2014 ticket ${String(data.ticketId)}`;
1557
+ case "emergency-correct":
1558
+ return `Emergency correction applied to ${String(data.nheId)}`;
1559
+ case "terminate":
1560
+ return `NHE terminated: ${String(data.nheId)} (reason: ${String(data.reason ?? "none")})`;
1561
+ case "deprecate":
1562
+ return `NHE deprecated: ${String(data.nheId)} (reason: ${String(data.reason ?? "none")})`;
1563
+ case "reactivate":
1564
+ return `NHE reactivated: ${String(data.nheId)}`;
1565
+ case "axiom-suggest":
1566
+ return `Axiom suggestion ${String(data.fromHimId)} \u2192 ${String(data.toHimId)}: "${String(data.statement)}"`;
1567
+ // ── 1.2 brain-as-code (Entries 16-24 of MAIC_HIM_NHE_INTERVIEW_LOG.md) ──
1568
+ case "opener":
1569
+ return `Proactive opener emitted by ${String(data.nheId)} for new user ${String(data.userId ?? "anonymous")}: "${String(data.text ?? "<elided>")}"`;
1570
+ case "nickname-attempt":
1571
+ return `Nickname attempt for ${String(data.nheId)}: "${String(data.attempted)}" \u2192 ${String(data.outcome ?? "pending")}`;
1572
+ case "reincarnate:model-swap":
1573
+ return `HIM reincarnated (model-swap): ${String(data.himId)} ${String(data.fromAdapter ?? "?")} \u2192 ${String(data.toAdapter ?? "?")}`;
1574
+ case "reincarnate:version-bump":
1575
+ return `HIM reincarnated (version-bump): ${String(data.himId)} ${String(data.fromVersion ?? "?")} \u2192 ${String(data.toVersion ?? "?")}`;
1576
+ case "reincarnate:return-from-limbo":
1577
+ return `HIM reincarnated (return-from-limbo): ${String(data.himId)} resumed after ${String(data.elapsedMs ?? 0)}ms of limbo`;
1578
+ case "dream:rem-spontaneous":
1579
+ return `Spontaneous REM dream for ${String(data.nheId)}: ${String(data.dreamId)} (dominant affect: ${String(data.dominantAffect ?? "unknown")})`;
1580
+ case "wake-affect:applied":
1581
+ return `Wake affect applied to ${String(data.nheId)}: ${String(data.affect)} (intensity ${String(data.intensity)}, halflife ${String(data.decayHalfLife)} interactions)`;
1582
+ case "wake-affect:decayed":
1583
+ return `Wake affect decayed for ${String(data.nheId)}: ${String(data.affect)} dissolved naturally`;
1584
+ case "sleep:suggested-by-maic":
1585
+ return `MAIC suggested sleep for ${String(data.nheId)} (reason: ${String(data.reason ?? "none")})`;
1586
+ case "sleep:declined-by-nhe":
1587
+ return `NHE ${String(data.nheId)} declined MAIC-suggested sleep (reason: ${String(data.reason ?? "none")})`;
1588
+ case "dream:soft-intervention-by-maic":
1589
+ return `MAIC soft-intervened on dream ${String(data.dreamId)} for ${String(data.nheId)} (reason: ${String(data.reason ?? "none")})`;
1590
+ case "amygdala:affect-assessed":
1591
+ return `Amygdala assessed input affect for ${String(data.nheId)}: ${String(data.detectedAffect ?? "neutral")} (risk multiplier ${String(data.riskMultiplier ?? 1)})`;
1592
+ case "hippocampus:memory-retrieved":
1593
+ return `Hippocampus retrieved ${String(data.memoryIds?.length ?? 0)} memories for ${String(data.nheId)}`;
1594
+ case "hippocampus:memory-consolidated":
1595
+ return `Hippocampus consolidated new memory ${String(data.memoryId)} for ${String(data.nheId)} (integrationIndex ${String(data.integrationIndex ?? 0)})`;
1596
+ case "prefrontal:deliberation":
1597
+ return `PFC deliberated for ${String(data.nheId)}: ${String(data.expressedOpenly ? "open" : "subtle")} (${String(data.affect ?? "neutral")})`;
1598
+ case "prefrontal:veto-amygdala":
1599
+ return `PFC vetoed amygdala impulse for ${String(data.nheId)}: ${String(data.originalImpulse ?? "?")} \u2192 ${String(data.resolvedAction ?? "?")} (downgrade ${String(data.downgradeRatio ?? "?")})`;
1600
+ case "affect:reconciliation":
1601
+ return `Affect reconciliation for ${String(data.nheId)}: day/night blend \u2192 ${String(data.resolvedAffect ?? "neutral")}`;
1602
+ case "cortex:dream-stored":
1603
+ return `Cortex stored dream ${String(data.dreamId)} for ${String(data.nheId)}`;
1604
+ case "cortex:active-imagination":
1605
+ return `Cortex generated active imagination for ${String(data.nheId)} (trigger: ${String(data.trigger ?? "user-requested")}, vividness ${String(data.vividness ?? 0)})`;
1606
+ case "temporal-lobe:snapshot-generated":
1607
+ return `Temporal-lobe snapshot ${String(data.snapshotId)} generated for HIM ${String(data.himId)} (reason: ${String(data.generatedBy ?? "self-decision")})`;
1608
+ case "limbo:enter":
1609
+ return `${String(data.nheId)} entered limbo (deep-coma) \u2014 reason: ${String(data.reason ?? "idle")}`;
1610
+ case "limbo:return":
1611
+ return `${String(data.nheId)} returned from limbo after ${String(data.elapsedMs ?? 0)}ms (reunion intensity ${String(data.reunionIntensity ?? "?")})`;
1612
+ default:
1613
+ return `Event ${ev.kind}`;
1614
+ }
1615
+ }
1616
+ var ALL_AUDIT_EVENT_KINDS = [
1617
+ // ── 1.0/1.1 core (17) ──
1618
+ "axiom-mint",
1619
+ "axiom-update",
1620
+ "axiom-retire",
1621
+ "him-register",
1622
+ "him-reincarnate",
1623
+ "proposal-emerge",
1624
+ "proposal-ratify",
1625
+ "proposal-reject",
1626
+ "behavior-review",
1627
+ "dream-induce",
1628
+ "dream-cancel",
1629
+ "dream-consume",
1630
+ "emergency-correct",
1631
+ "deprecate",
1632
+ "terminate",
1633
+ "reactivate",
1634
+ "axiom-suggest",
1635
+ // ── 1.2 brain-as-code (22, Entries 16-24) ──
1636
+ "opener",
1637
+ "nickname-attempt",
1638
+ "reincarnate:model-swap",
1639
+ "reincarnate:version-bump",
1640
+ "reincarnate:return-from-limbo",
1641
+ "dream:rem-spontaneous",
1642
+ "wake-affect:applied",
1643
+ "wake-affect:decayed",
1644
+ "sleep:suggested-by-maic",
1645
+ "sleep:declined-by-nhe",
1646
+ "dream:soft-intervention-by-maic",
1647
+ "amygdala:affect-assessed",
1648
+ "hippocampus:memory-retrieved",
1649
+ "hippocampus:memory-consolidated",
1650
+ "prefrontal:deliberation",
1651
+ "prefrontal:veto-amygdala",
1652
+ "affect:reconciliation",
1653
+ "cortex:dream-stored",
1654
+ "cortex:active-imagination",
1655
+ "temporal-lobe:snapshot-generated",
1656
+ "limbo:enter",
1657
+ "limbo:return"
1658
+ ];
1659
+ var GENESIS = "GENESIS";
1660
+ var AuditLog = class _AuditLog {
1661
+ constructor(storeDir) {
1662
+ this.storeDir = storeDir;
1663
+ this.logPath = join(storeDir, "audit", "log.ndjson");
1664
+ }
1665
+ storeDir;
1666
+ logPath;
1667
+ events = [];
1668
+ lastHash = GENESIS;
1669
+ static async open(storeDir) {
1670
+ const log = new _AuditLog(storeDir);
1671
+ await mkdir(join(storeDir, "audit"), { recursive: true });
1672
+ await log.loadAndVerify();
1673
+ return log;
1674
+ }
1675
+ async append(input) {
1676
+ const event = {
1677
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1678
+ kind: input.kind,
1679
+ auditId: ulid(),
1680
+ data: input.data,
1681
+ prevHash: this.lastHash,
1682
+ thisHash: ""
1683
+ };
1684
+ event.thisHash = computeHash(event);
1685
+ await appendFile(this.logPath, `${JSON.stringify(event)}
1686
+ `, "utf-8");
1687
+ this.events.push(event);
1688
+ this.lastHash = event.thisHash;
1689
+ return event;
1690
+ }
1691
+ async *query(filter) {
1692
+ for (const e of this.events) {
1693
+ if (filter.kind && e.kind !== filter.kind) continue;
1694
+ if (filter.since && e.ts < filter.since) continue;
1695
+ if (filter.until && e.ts > filter.until) continue;
1696
+ if (filter.nheId && e.data.nheId !== filter.nheId) continue;
1697
+ if (filter.himId && e.data.himId !== filter.himId) continue;
1698
+ yield e;
1699
+ }
1700
+ }
1701
+ /** Total number of events appended. */
1702
+ size() {
1703
+ return this.events.length;
1704
+ }
1705
+ // ─── internals ──────────────────────────────────────────────────────
1706
+ async loadAndVerify() {
1707
+ let raw;
1708
+ try {
1709
+ raw = await readFile(this.logPath, "utf-8");
1710
+ } catch (err) {
1711
+ if (err.code === "ENOENT") return;
1712
+ throw err;
1713
+ }
1714
+ const lines = raw.split("\n").filter((l) => l.length > 0);
1715
+ let prev = GENESIS;
1716
+ for (let i = 0; i < lines.length; i++) {
1717
+ const parsed = JSON.parse(lines[i]);
1718
+ if (parsed.prevHash !== prev) {
1719
+ throw new Error(
1720
+ `AuditLog: chain tampered at line ${i + 1} (prevHash mismatch). expected ${prev}, found ${parsed.prevHash}`
1721
+ );
1722
+ }
1723
+ const recomputed = computeHash(parsed);
1724
+ if (recomputed !== parsed.thisHash) {
1725
+ throw new Error(
1726
+ `AuditLog: tamper detected at line ${i + 1} (thisHash mismatch).`
1727
+ );
1728
+ }
1729
+ this.events.push(parsed);
1730
+ prev = parsed.thisHash;
1731
+ }
1732
+ this.lastHash = prev;
1733
+ }
1734
+ };
1735
+ function computeHash(e) {
1736
+ const payload = canonicalJSON({
1737
+ ts: e.ts,
1738
+ kind: e.kind,
1739
+ auditId: e.auditId,
1740
+ data: e.data,
1741
+ prevHash: e.prevHash
1742
+ });
1743
+ const h = createHash("sha256").update(payload).digest("hex");
1744
+ return `sha256:${h}`;
1745
+ }
1746
+
1747
+ // src/audit/retention.ts
1748
+ var DEFAULT_RETENTION_DAYS = {
1749
+ // Cosmologically permanent — the axiom record.
1750
+ "axiom-mint": Number.POSITIVE_INFINITY,
1751
+ "axiom-update": Number.POSITIVE_INFINITY,
1752
+ "axiom-retire": Number.POSITIVE_INFINITY,
1753
+ "axiom-suggest": Number.POSITIVE_INFINITY,
1754
+ "proposal-emerge": Number.POSITIVE_INFINITY,
1755
+ "proposal-ratify": Number.POSITIVE_INFINITY,
1756
+ "proposal-reject": Number.POSITIVE_INFINITY,
1757
+ // Long-term — compliance evidence. Five years matches typical
1758
+ // financial/healthcare audit windows and exceeds the EU AI Act's
1759
+ // record-keeping floor.
1760
+ "him-register": 365 * 5,
1761
+ "him-reincarnate": 365 * 5,
1762
+ "behavior-review": 365 * 5,
1763
+ "dream-induce": 365 * 5,
1764
+ "terminate": 365 * 5,
1765
+ "deprecate": 365 * 5,
1766
+ "reactivate": 365 * 5,
1767
+ "emergency-correct": 365 * 5,
1768
+ // Operational — short-term bookkeeping for in-flight tickets.
1769
+ "dream-cancel": 90,
1770
+ "dream-consume": 90,
1771
+ // ── 1.2 brain-as-code (Entries 16-24) ──
1772
+ // Permanent — cosmological identity continuity.
1773
+ "reincarnate:model-swap": Number.POSITIVE_INFINITY,
1774
+ "reincarnate:version-bump": Number.POSITIVE_INFINITY,
1775
+ "reincarnate:return-from-limbo": Number.POSITIVE_INFINITY,
1776
+ "temporal-lobe:snapshot-generated": Number.POSITIVE_INFINITY,
1777
+ "limbo:enter": Number.POSITIVE_INFINITY,
1778
+ "limbo:return": Number.POSITIVE_INFINITY,
1779
+ // Long-term — governance / deliberation evidence (5 years).
1780
+ "opener": 365 * 5,
1781
+ "nickname-attempt": 365 * 5,
1782
+ "dream:rem-spontaneous": 365 * 5,
1783
+ "sleep:suggested-by-maic": 365 * 5,
1784
+ "sleep:declined-by-nhe": 365 * 5,
1785
+ "dream:soft-intervention-by-maic": 365 * 5,
1786
+ "amygdala:affect-assessed": 365 * 5,
1787
+ "hippocampus:memory-retrieved": 365 * 5,
1788
+ "hippocampus:memory-consolidated": 365 * 5,
1789
+ "prefrontal:deliberation": 365 * 5,
1790
+ "prefrontal:veto-amygdala": 365 * 5,
1791
+ "cortex:dream-stored": 365 * 5,
1792
+ "cortex:active-imagination": 365 * 5,
1793
+ // Operational — ephemeral runtime state.
1794
+ "wake-affect:applied": 90,
1795
+ "wake-affect:decayed": 90,
1796
+ "affect:reconciliation": 90
1797
+ };
1798
+ function evaluateRetention(events, opts = {}) {
1799
+ const now = opts.now ?? /* @__PURE__ */ new Date();
1800
+ const policy = { ...DEFAULT_RETENTION_DAYS, ...opts.policy };
1801
+ const nowMs = now.getTime();
1802
+ const dayMs = 24 * 60 * 60 * 1e3;
1803
+ const decisions = events.map((ev) => {
1804
+ const ageMs = nowMs - new Date(ev.ts).getTime();
1805
+ const ageDays = ageMs / dayMs;
1806
+ const retentionDays = policy[ev.kind] ?? Number.POSITIVE_INFINITY;
1807
+ const status = ageDays > retentionDays ? "candidate-for-archive" : "keep";
1808
+ return { auditId: ev.auditId, kind: ev.kind, ageDays, retentionDays, status };
1809
+ });
1810
+ decisions.sort((a, b) => b.ageDays - a.ageDays);
1811
+ const keepCount = decisions.filter((d) => d.status === "keep").length;
1812
+ const archiveCandidateCount = decisions.length - keepCount;
1813
+ return {
1814
+ generatedAt: now.toISOString(),
1815
+ totalEvents: events.length,
1816
+ keepCount,
1817
+ archiveCandidateCount,
1818
+ decisions
1819
+ };
1820
+ }
1821
+ var LocalMaic = class _LocalMaic {
1822
+ constructor(config, axioms, hims, inductions, nheStatuses, proposals, audit, review) {
1823
+ this.config = config;
1824
+ this.axioms = axioms;
1825
+ this.hims = hims;
1826
+ this.inductions = inductions;
1827
+ this.nheStatuses = nheStatuses;
1828
+ this.proposals = proposals;
1829
+ this.audit = audit;
1830
+ this.review = review;
1831
+ }
1832
+ config;
1833
+ axioms;
1834
+ hims;
1835
+ inductions;
1836
+ nheStatuses;
1837
+ proposals;
1838
+ audit;
1839
+ review;
1840
+ /** Pinned Creator public key for this MAIC instance (base64url). */
1841
+ get creatorPublicKey() {
1842
+ return this.config.creatorPublicKey;
1843
+ }
1844
+ static async open(config) {
1845
+ const axioms = await AxiomStore.open(config.storeDir, config.creatorPublicKey);
1846
+ const hims = await HimStore.open(config.storeDir, config.creatorPublicKey);
1847
+ const inductions = await InductionStore.open(config.storeDir);
1848
+ const nheStatuses = await NheStatusStore.open(config.storeDir, config.creatorPublicKey);
1849
+ const proposals = await ProposalStore.open(config.storeDir, config.creatorPublicKey);
1850
+ const audit = await AuditLog.open(config.storeDir);
1851
+ const packs = [DEFAULT_RULE_PACK, ...config.additionalRulePacks ?? []];
1852
+ const review = new ReviewPipeline(packs);
1853
+ return new _LocalMaic(config, axioms, hims, inductions, nheStatuses, proposals, audit, review);
1854
+ }
1855
+ /**
1856
+ * Bootstrap: mint each SEED_AXIOM with a Creator signature.
1857
+ * Idempotent — skips axioms whose id is already present.
1858
+ * Uses a reserved high-range of nonces so seed bootstrap never collides with
1859
+ * operational nonces (which grow from 0 upward).
1860
+ */
1861
+ async seed(keyring) {
1862
+ if (keyring.publicKey() !== this.config.creatorPublicKey) {
1863
+ throw new Error("LocalMaic.seed: keyring does not match pinned Creator public key");
1864
+ }
1865
+ let minted = 0;
1866
+ let skipped = 0;
1867
+ for (let i = 0; i < SEED_AXIOMS.length; i++) {
1868
+ const req = SEED_AXIOMS[i];
1869
+ const existing = await this.axioms.get(req.id);
1870
+ if (existing) {
1871
+ skipped++;
1872
+ continue;
1873
+ }
1874
+ const sig = keyring.sign(req, SEED_NONCE_BASE + i);
1875
+ const axiom = await this.axioms.mint(req, sig);
1876
+ await this.audit.append({
1877
+ kind: "axiom-mint",
1878
+ data: { axiomId: axiom.id, rank: axiom.rank, source: axiom.source, origin: "seed" }
1879
+ });
1880
+ minted++;
1881
+ }
1882
+ return { minted, skipped };
1883
+ }
1884
+ async mintAxiom(req, sig) {
1885
+ const axiom = await this.axioms.mint(req, sig);
1886
+ await this.audit.append({
1887
+ kind: "axiom-mint",
1888
+ data: { axiomId: axiom.id, rank: axiom.rank, source: axiom.source, origin: "custom" }
1889
+ });
1890
+ return axiom;
1891
+ }
1892
+ async listAxioms(filter) {
1893
+ return this.axioms.list(filter);
1894
+ }
1895
+ async getAxiom(id) {
1896
+ return this.axioms.get(id);
1897
+ }
1898
+ /**
1899
+ * Project the Ontological Kernel (OKL) of this MAIC instance or of a registered HIM.
1900
+ *
1901
+ * The OKL is the typed projection described in `THE_SOUL_OF_THE_MACHINE.md`
1902
+ * §3.1 + Appendix A.2.1: a `metaAxiomId` hoisted at position 0, the remaining
1903
+ * axioms ordered by rank hierarchy (`meta → primary → secondary`), optionally
1904
+ * narrowed by `jurisdiction` and tagged with a `himId`.
1905
+ *
1906
+ * Without `himId`: returns the kernel of the root MAIC corpus (every axiom
1907
+ * currently in the store). With `himId`: returns the HIM-specific kernel
1908
+ * built from `axiomsSnapshot ∪ emergentAxioms`, tagged with the HIM id so
1909
+ * downstream tooling (Φ′ runner, compliance auditors) can attribute the
1910
+ * kernel. Throws when `himId` does not resolve to a registered HIM.
1911
+ *
1912
+ * Closes TASK.md D-M6.
1913
+ */
1914
+ async getOntologicalKernel(himId, opts = {}) {
1915
+ if (himId === void 0) {
1916
+ const axioms2 = await this.listAxioms();
1917
+ return projectOntologicalKernel(axioms2, opts);
1918
+ }
1919
+ const him = await this.getHimRecord(himId);
1920
+ if (!him) {
1921
+ throw new Error(`HIM not registered: ${himId}`);
1922
+ }
1923
+ const axioms = [...him.axiomsSnapshot, ...him.emergentAxioms];
1924
+ return projectOntologicalKernel(axioms, { ...opts, himId });
1925
+ }
1926
+ /**
1927
+ * Register a HIM in this MAIC instance. Snapshots the current axiom corpus
1928
+ * (the HIM's inherited axioms at birth) and emits a `him-register` audit event.
1929
+ *
1930
+ * Future axiom mints in MAIC do NOT retroactively change a HIM's snapshot;
1931
+ * HIM-emergent evolutions land via a separate channel (see `proposeAxiomEvolution`).
1932
+ */
1933
+ async registerHim(birthSig, creatorSig) {
1934
+ const parsed = BirthSignature.parse(birthSig);
1935
+ const axiomsSnapshot = await this.axioms.list();
1936
+ const audit = await this.audit.append({
1937
+ kind: "him-register",
1938
+ data: {
1939
+ himId: parsed.himId,
1940
+ primaryArchetype: parsed.primaryArchetype,
1941
+ bornAt: parsed.bornAt,
1942
+ axiomCount: axiomsSnapshot.length
1943
+ }
1944
+ });
1945
+ return this.hims.register(parsed, creatorSig, axiomsSnapshot, audit.auditId);
1946
+ }
1947
+ async getHimRecord(himId) {
1948
+ return this.hims.get(himId);
1949
+ }
1950
+ async listHims() {
1951
+ return this.hims.list();
1952
+ }
1953
+ /**
1954
+ * Reincarnate a HIM into a new NHE body (Entries 3 + 4 + J-H3 lifecycle).
1955
+ * Same HIM persists; new NHE inherits axiom snapshot from registration time.
1956
+ * Previous open body (if `req.fromNheId` given) is closed atomically.
1957
+ *
1958
+ * Requires a Creator signature over the canonical request payload.
1959
+ *
1960
+ * Audit emission (closes F6 + F7 from the 2026-05-24 him deep audit):
1961
+ *
1962
+ * - When `opts.lifecycle` is **omitted**, emits the generic
1963
+ * `him-reincarnate` audit kind (legacy / backward-compatible path).
1964
+ * `data` carries `himId`, `fromNheId`, `toNheId`, `toLlmAdapter`,
1965
+ * `reason`, `bodyHistoryLength`.
1966
+ * - When `opts.lifecycle` is **provided** (`model-swap` /
1967
+ * `version-bump` / `return-from-limbo`), emits the typed
1968
+ * `reincarnate:${lifecycle}` audit kind instead, with the same
1969
+ * `data` shape plus a redundant `lifecycle` field so consumers
1970
+ * reading either the `kind` or `data` can recover the
1971
+ * classification.
1972
+ *
1973
+ * `@teleologyhi-sdk/him`'s `reincarnate` helper always supplies a
1974
+ * lifecycle (defaulting to `"model-swap"`), so HIM-routed events
1975
+ * always land under the typed kinds. Direct `maic.reincarnateHim`
1976
+ * callers that ignore `opts` keep getting `him-reincarnate` for
1977
+ * compatibility.
1978
+ */
1979
+ async reincarnateHim(req, creatorSig, opts = {}) {
1980
+ const updated = await this.hims.reincarnate(req, creatorSig);
1981
+ const newBody = updated.bodyHistory[updated.bodyHistory.length - 1];
1982
+ const kind = opts.lifecycle ? `reincarnate:${opts.lifecycle}` : "him-reincarnate";
1983
+ await this.audit.append({
1984
+ kind,
1985
+ data: {
1986
+ himId: req.himId,
1987
+ fromNheId: req.fromNheId ?? null,
1988
+ toNheId: newBody.nheId,
1989
+ toLlmAdapter: newBody.llmAdapter,
1990
+ reason: req.reason ?? null,
1991
+ bodyHistoryLength: updated.bodyHistory.length,
1992
+ ...opts.lifecycle ? { lifecycle: opts.lifecycle } : {}
1993
+ }
1994
+ });
1995
+ return updated;
1996
+ }
1997
+ /**
1998
+ * Lifecycle controls (Entry 5).
1999
+ *
2000
+ * - `terminate` marks an NHE permanently inactive. NHE.respond/sleep should
2001
+ * refuse all calls. Reversible only via Creator-signed `reactivate`.
2002
+ * - `deprecate` marks an NHE as soft-retired. NHE.respond should still work
2003
+ * but emit a deprecation warning. Reversible via `reactivate`.
2004
+ * - `reactivate` brings a deprecated or terminated NHE back to active.
2005
+ *
2006
+ * All three require a Creator signature over the canonical request payload.
2007
+ * Unknown nheIds are implicitly active; status records are only persisted
2008
+ * when state changes.
2009
+ */
2010
+ async terminate(nheId, reason, creatorSig) {
2011
+ return this.applyLifecycle({ op: "terminate", nheId, ...reason !== void 0 ? { reason } : {} }, creatorSig);
2012
+ }
2013
+ async deprecate(nheId, reason, creatorSig) {
2014
+ return this.applyLifecycle({ op: "deprecate", nheId, ...reason !== void 0 ? { reason } : {} }, creatorSig);
2015
+ }
2016
+ async reactivate(nheId, reason, creatorSig) {
2017
+ return this.applyLifecycle({ op: "reactivate", nheId, ...reason !== void 0 ? { reason } : {} }, creatorSig);
2018
+ }
2019
+ /** Current status. Returns "active" when no record exists. */
2020
+ async getNheStatus(nheId) {
2021
+ return this.nheStatuses.resolve(nheId);
2022
+ }
2023
+ /** Full status record (or null when never altered). */
2024
+ async getNheStatusRecord(nheId) {
2025
+ return this.nheStatuses.get(nheId);
2026
+ }
2027
+ /** Enumerate NHEs with persisted status (optionally filter by status). */
2028
+ async listNheStatuses(filter = {}) {
2029
+ return this.nheStatuses.list(filter);
2030
+ }
2031
+ async applyLifecycle(req, sig) {
2032
+ const updated = await this.nheStatuses.apply(req, sig);
2033
+ await this.audit.append({
2034
+ kind: req.op === "terminate" ? "terminate" : req.op === "deprecate" ? "deprecate" : "reactivate",
2035
+ data: {
2036
+ nheId: req.nheId,
2037
+ status: updated.status,
2038
+ reason: req.reason ?? null,
2039
+ since: updated.since
2040
+ }
2041
+ });
2042
+ return updated;
2043
+ }
2044
+ /**
2045
+ * Queue a dream-induction ticket for the given NHE (Entry 2).
2046
+ *
2047
+ * NHE picks the oldest pending ticket on its next sleep cycle, runs REM with
2048
+ * the configured scenario, then marks the ticket consumed. Tickets persist
2049
+ * across restarts and are reflected in the audit log.
2050
+ */
2051
+ async induceDream(nheId, intent) {
2052
+ const ticket = await this.inductions.induce(nheId, intent);
2053
+ await this.audit.append({
2054
+ kind: "dream-induce",
2055
+ data: {
2056
+ nheId,
2057
+ ticketId: ticket.id,
2058
+ inducedBy: intent.inducedBy,
2059
+ scenario: intent.scenario,
2060
+ desiredLearning: intent.desiredLearning
2061
+ }
2062
+ });
2063
+ return ticket;
2064
+ }
2065
+ /** List pending induction tickets for an NHE (oldest first). */
2066
+ async listPendingInductions(nheId) {
2067
+ return this.inductions.listPending(nheId);
2068
+ }
2069
+ /** Look up any induction ticket by id. */
2070
+ async getInduction(ticketId) {
2071
+ return this.inductions.get(ticketId);
2072
+ }
2073
+ /** Cancel a pending induction. Idempotent only when already-cancelled tickets are rejected. */
2074
+ async cancelInduction(ticketId, reason) {
2075
+ const updated = await this.inductions.cancel(ticketId, reason);
2076
+ await this.audit.append({
2077
+ kind: "dream-cancel",
2078
+ data: { nheId: updated.nheId, ticketId, reason: reason ?? null }
2079
+ });
2080
+ return updated;
2081
+ }
2082
+ /** Mark a pending ticket as consumed (NHE calls this after successful sleep). */
2083
+ async consumeInduction(ticketId) {
2084
+ const updated = await this.inductions.consume(ticketId);
2085
+ await this.audit.append({
2086
+ kind: "dream-consume",
2087
+ data: { nheId: updated.nheId, ticketId }
2088
+ });
2089
+ return updated;
2090
+ }
2091
+ /**
2092
+ * Review a behavior report against the active rule packs. The verdict is
2093
+ * logged to the audit chain as a single tamper-evident event whose auditId
2094
+ * becomes the verdict's `auditId`.
2095
+ */
2096
+ async reviewBehavior(report) {
2097
+ const parsed = BehaviorReport.parse(report);
2098
+ const partial = this.review.review(parsed);
2099
+ const event = await this.audit.append({
2100
+ kind: "behavior-review",
2101
+ data: {
2102
+ nheId: parsed.nheId,
2103
+ himId: parsed.himId,
2104
+ actionKind: parsed.actionKind,
2105
+ riskTags: parsed.riskTags,
2106
+ verdict: partial
2107
+ }
2108
+ });
2109
+ return { ...partial, auditId: event.auditId };
2110
+ }
2111
+ /**
2112
+ * Queue a HIM-emergent axiom proposal (Entry 7). The proposal enters
2113
+ * `pending` status; the Creator decides out of band via `ratifyAxiomProposal`
2114
+ * or `rejectAxiomProposal`. Emits a `proposal-emerge` audit event.
2115
+ *
2116
+ * Returns an `AxiomEvolutionResult` with `outcome: "deferred-for-creator-review"`
2117
+ * and `proposalId`. Poll `getAxiomProposal(proposalId)` for the final state.
2118
+ */
2119
+ async proposeAxiomEvolution(himId, proposal) {
2120
+ if (!await this.hims.get(himId)) {
2121
+ throw new Error(`LocalMaic.proposeAxiomEvolution: himId "${himId}" not registered`);
2122
+ }
2123
+ const record = await this.proposals.propose(himId, proposal);
2124
+ await this.audit.append({
2125
+ kind: "proposal-emerge",
2126
+ data: {
2127
+ himId,
2128
+ proposalId: record.id,
2129
+ rank: proposal.candidate.rank,
2130
+ statement: proposal.candidate.statement,
2131
+ derivedFromDreamIds: proposal.derivedFromDreamIds,
2132
+ derivedFromInteractionIds: proposal.derivedFromInteractionIds
2133
+ }
2134
+ });
2135
+ return {
2136
+ outcome: "deferred-for-creator-review",
2137
+ proposalId: record.id
2138
+ };
2139
+ }
2140
+ /** Look up a proposal by id (or null when not found). */
2141
+ async getAxiomProposal(proposalId) {
2142
+ return this.proposals.get(proposalId);
2143
+ }
2144
+ /** List proposals, optionally filtered by `himId` and/or `status`. */
2145
+ async listAxiomProposals(filter = {}) {
2146
+ return this.proposals.list(filter);
2147
+ }
2148
+ /**
2149
+ * Ratify a pending proposal (Creator-signed). On success, mints the
2150
+ * candidate as a new `Axiom` (source: "him-emergent"), appends to the
2151
+ * HIM's `emergentAxioms`, and emits a `proposal-ratify` audit event.
2152
+ * Throws if the proposal is not pending or the signature is invalid.
2153
+ */
2154
+ async ratifyAxiomProposal(proposalId, creatorSig) {
2155
+ const req = { op: "ratify", proposalId };
2156
+ const pending = this.proposals.get(proposalId);
2157
+ const record = await pending;
2158
+ if (!record) {
2159
+ throw new Error(`LocalMaic.ratifyAxiomProposal: proposal "${proposalId}" not found`);
2160
+ }
2161
+ const candidate = record.proposal.candidate;
2162
+ const newAxiomId = `ax.him.${record.himId}.${ulid()}`;
2163
+ const axiom = {
2164
+ id: newAxiomId,
2165
+ rank: candidate.rank,
2166
+ statement: candidate.statement,
2167
+ weight: candidate.weight,
2168
+ flexibility: candidate.flexibility,
2169
+ source: "him-emergent",
2170
+ immutable: candidate.immutable,
2171
+ ...candidate.jurisdictions ? { jurisdictions: candidate.jurisdictions } : {},
2172
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2173
+ };
2174
+ const ratified = await this.proposals.markRatified(req, creatorSig, newAxiomId);
2175
+ await this.hims.appendEmergentAxiom(record.himId, axiom);
2176
+ await this.audit.append({
2177
+ kind: "proposal-ratify",
2178
+ data: {
2179
+ himId: record.himId,
2180
+ proposalId,
2181
+ axiomId: newAxiomId,
2182
+ rank: axiom.rank
2183
+ }
2184
+ });
2185
+ return { proposal: ratified, axiom };
2186
+ }
2187
+ /**
2188
+ * Reject a pending proposal (Creator-signed). Records the rejection on the
2189
+ * proposal record (status → "rejected" + timestamp + optional reason) and
2190
+ * emits a `proposal-reject` audit event.
2191
+ */
2192
+ async rejectAxiomProposal(proposalId, reason, creatorSig) {
2193
+ const req = {
2194
+ op: "reject",
2195
+ proposalId,
2196
+ ...reason !== void 0 ? { reason } : {}
2197
+ };
2198
+ const rejected = await this.proposals.markRejected(req, creatorSig);
2199
+ await this.audit.append({
2200
+ kind: "proposal-reject",
2201
+ data: {
2202
+ himId: rejected.himId,
2203
+ proposalId,
2204
+ reason: reason ?? null
2205
+ }
2206
+ });
2207
+ return rejected;
2208
+ }
2209
+ /**
2210
+ * **Society of HIMs — axiom suggestion channel (E11).**
2211
+ *
2212
+ * One HIM proposes an axiom to another. The transfer is **not direct** —
2213
+ * the suggestion is recorded in the audit log and the receiving HIM is
2214
+ * expected to relay it through `proposeAxiomEvolution` as if it had
2215
+ * derived the candidate itself; the Creator still ratifies via the
2216
+ * existing channel. This preserves the Kardecist invariant ("each
2217
+ * spirit evolves through lived experience") while permitting cross-HIM
2218
+ * cross-pollination.
2219
+ *
2220
+ * The Creator must sign the suggestion request so HIMs cannot collude
2221
+ * around the gate.
2222
+ */
2223
+ async suggestAxiomToHim(req, creatorSig) {
2224
+ if (!CreatorKeyring.verifyWith(this.creatorPublicKey, req, creatorSig)) {
2225
+ throw new Error("LocalMaic.suggestAxiomToHim: invalid Creator signature");
2226
+ }
2227
+ const fromRec = await this.hims.get(req.fromHimId);
2228
+ const toRec = await this.hims.get(req.toHimId);
2229
+ if (!fromRec) {
2230
+ throw new Error(
2231
+ `LocalMaic.suggestAxiomToHim: fromHimId "${req.fromHimId}" not registered`
2232
+ );
2233
+ }
2234
+ if (!toRec) {
2235
+ throw new Error(
2236
+ `LocalMaic.suggestAxiomToHim: toHimId "${req.toHimId}" not registered`
2237
+ );
2238
+ }
2239
+ const event = await this.audit.append({
2240
+ kind: "axiom-suggest",
2241
+ data: {
2242
+ fromHimId: req.fromHimId,
2243
+ toHimId: req.toHimId,
2244
+ statement: req.statement,
2245
+ rank: req.rank,
2246
+ rationale: req.rationale ?? null
2247
+ }
2248
+ });
2249
+ return { auditId: event.auditId };
2250
+ }
2251
+ /**
2252
+ * Project the audit log into compliance evidence for a target framework
2253
+ * (Entry 5 + RESEARCH_DOSSIER §5.6). Group every recorded event by which
2254
+ * control(s) it supports; surface `uncoveredKinds` for events the mapper
2255
+ * does not yet know how to project.
2256
+ */
2257
+ async toCompliance(framework, opts = {}) {
2258
+ return ComplianceMapper.project(this.audit, framework, opts);
2259
+ }
2260
+ /** Query the audit log. */
2261
+ queryAudit(filter) {
2262
+ return this.audit.query(filter);
2263
+ }
2264
+ /** Number of audit events recorded since the store was opened. */
2265
+ auditSize() {
2266
+ return this.audit.size();
2267
+ }
2268
+ /**
2269
+ * Per-kind retention classification (E3). Tells the operator which
2270
+ * audit events have aged past their retention window and should be
2271
+ * moved to encrypted cold-storage. Tamper-evident hash chain forbids
2272
+ * actual deletion in-place — this method only classifies. See
2273
+ * `audit/retention.ts` for the policy defaults.
2274
+ */
2275
+ async auditRetentionReport(opts = {}) {
2276
+ const events = [];
2277
+ for await (const e of this.audit.query({})) events.push(e);
2278
+ return evaluateRetention(events, opts);
2279
+ }
2280
+ };
2281
+ var SEED_NONCE_BASE = 4294901760;
2282
+
2283
+ // src/client/remote.ts
2284
+ var RemoteMaic = class {
2285
+ baseUrl;
2286
+ apiKey;
2287
+ fetchFn;
2288
+ timeoutMs;
2289
+ constructor(config) {
2290
+ if (!config.baseUrl) {
2291
+ throw new Error("RemoteMaic: baseUrl is required");
2292
+ }
2293
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
2294
+ if (config.apiKey !== void 0) this.apiKey = config.apiKey;
2295
+ this.fetchFn = config.fetch ?? globalThis.fetch;
2296
+ this.timeoutMs = config.timeoutMs ?? 1e4;
2297
+ }
2298
+ /**
2299
+ * `reviewBehavior` is **fail-closed** (E4 — PROPOSED_DECISIONS.md). If the
2300
+ * remote service is unreachable, throw — no governance, no response.
2301
+ * The NHE will surface this as a refusal upstream.
2302
+ */
2303
+ async reviewBehavior(report) {
2304
+ return this.request("POST", "/v1/behavior-review", report);
2305
+ }
2306
+ /**
2307
+ * `getNheStatus` defaults to **"active"** when unreachable (E4). The
2308
+ * Kardecist invariant: an unreachable governance doesn't kill the
2309
+ * spirit. Operators who want fail-closed on lifecycle should wrap with
2310
+ * a watchdog that hard-fails the deployment when the remote drops.
2311
+ */
2312
+ async getNheStatus(nheId) {
2313
+ try {
2314
+ const body = await this.request(
2315
+ "GET",
2316
+ `/v1/nhes/${encodeURIComponent(nheId)}/status`
2317
+ );
2318
+ return body.status;
2319
+ } catch {
2320
+ return "active";
2321
+ }
2322
+ }
2323
+ /**
2324
+ * `listPendingInductions` is **fail-open** (E4). No inductions = NHE
2325
+ * skips them and continues the sleep cycle; this is best-effort by
2326
+ * design.
2327
+ */
2328
+ async listPendingInductions(nheId) {
2329
+ try {
2330
+ const body = await this.request(
2331
+ "GET",
2332
+ `/v1/nhes/${encodeURIComponent(nheId)}/inductions/pending`
2333
+ );
2334
+ return body.tickets;
2335
+ } catch {
2336
+ return [];
2337
+ }
2338
+ }
2339
+ /**
2340
+ * `consumeInduction` is **fail-open** (E4). If the consume call fails, we
2341
+ * return a synthetic *pending* placeholder so the caller treats the
2342
+ * induction as still-unconsumed and re-tries on the next sleep cycle.
2343
+ *
2344
+ * The placeholder uses placeholder values (`nheId: "unknown"`, epoch
2345
+ * `createdAt`) so it is visibly synthetic in logs/audits, but the shape
2346
+ * is **strictly valid**: `status === "pending"` carries no
2347
+ * `cancelReason`/`cancelledAt`/`consumedAt`, which avoids the
2348
+ * shape-contradiction of a "pending ticket with a cancel reason".
2349
+ * Operators who need the transport-failure reason should observe the
2350
+ * underlying fetch error (e.g. via OpenTelemetry traces) rather than
2351
+ * trying to read it off the ticket.
2352
+ */
2353
+ async consumeInduction(ticketId) {
2354
+ try {
2355
+ return await this.request(
2356
+ "POST",
2357
+ `/v1/inductions/${encodeURIComponent(ticketId)}/consume`
2358
+ );
2359
+ } catch {
2360
+ return {
2361
+ id: ticketId,
2362
+ nheId: "unknown",
2363
+ intent: { scenario: "", desiredLearning: "", inducedBy: "maic" },
2364
+ status: "pending",
2365
+ createdAt: (/* @__PURE__ */ new Date(0)).toISOString()
2366
+ };
2367
+ }
2368
+ }
2369
+ async request(method, path, body) {
2370
+ const url = `${this.baseUrl}${path}`;
2371
+ const headers = { accept: "application/json" };
2372
+ if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;
2373
+ if (body !== void 0) headers["content-type"] = "application/json";
2374
+ const controller = new AbortController();
2375
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
2376
+ try {
2377
+ const init = { method, headers, signal: controller.signal };
2378
+ if (body !== void 0) init.body = JSON.stringify(body);
2379
+ const res = await this.fetchFn(url, init);
2380
+ if (!res.ok) {
2381
+ const text = await safeReadText(res);
2382
+ throw new Error(
2383
+ `RemoteMaic: HTTP ${res.status} ${res.statusText} on ${method} ${path}: ${text}`
2384
+ );
2385
+ }
2386
+ return await res.json();
2387
+ } finally {
2388
+ clearTimeout(timer);
2389
+ }
2390
+ }
2391
+ };
2392
+ async function safeReadText(r) {
2393
+ try {
2394
+ return await r.text();
2395
+ } catch {
2396
+ return "<unreadable>";
2397
+ }
2398
+ }
2399
+
2400
+ export { ALL_AUDIT_EVENT_KINDS, Affect, ArchetypeModifier, AstrologicalAspect, AuditLog, Axiom, AxiomProposalRecord, AxiomRank, AxiomSource, AxiomStore, BehaviorReport, BirthSignature, ComplianceMapper, CreatorKeyring, CreatorSignature, DEFAULT_RETENTION_DAYS, DEFAULT_RULE_PACK, DreamInductionIntent, DreamInductionTicket, EU_AI_ACT_MAPPING, EmergentAxiomCandidate, EmergentAxiomProposal, HimStore, ISO_42001_MAPPING, IdentityLayer, IdentitySnapshot, InductionStatus, InductionStore, InteractionRecord, InvalidBirthSignatureError, LimboReturn, LimboState, LimboTransition, LocalMaic, META_AXIOM_ID, MaicVerdict, MemoryRecord, NatalChart, NatalChartAspect, NatalChartPosition, NatalPlanet, NheBodyRef, NheStatus, NheStatusRecord, NheStatusStore, ProposalStatus, ProposalStore, ReasoningStep, RemoteMaic, ReviewPipeline, SEED_AXIOMS, SEED_NONCE_BASE, SIGNED_BIRTH_FIELDS, SemioticPattern, SemioticSign, TeleologicalOrientation, VerdictKind, WakeAffectBias, ZodiacSign, assertBirthSignature, canonicalJSON, evaluateRetention, projectOntologicalKernel, signBirthSignature, signedBirthPayload, verifyBirthSignature };
2401
+ //# sourceMappingURL=index.js.map
2402
+ //# sourceMappingURL=index.js.map