open-multi-agent-kit 0.79.3 → 0.80.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/MATURITY.md +2 -2
  3. package/README.md +86 -39
  4. package/ROADMAP.md +20 -17
  5. package/dist/brand/night-city.theme.json +122 -24
  6. package/dist/brand/rust-forge.theme.json +1 -1
  7. package/dist/commands/chat/native-root-loop.d.ts +27 -3
  8. package/dist/commands/chat/native-root-loop.js +370 -49
  9. package/dist/commands/dag.js +45 -0
  10. package/dist/commands/init/content.d.ts +1 -1
  11. package/dist/commands/init/content.js +3 -3
  12. package/dist/commands/init.js +3 -3
  13. package/dist/commands/verify.js +59 -1
  14. package/dist/contracts/dag.d.ts +9 -1
  15. package/dist/evidence/graph-ontology-relation-gate.d.ts +10 -0
  16. package/dist/evidence/graph-ontology-relation-gate.js +46 -0
  17. package/dist/evidence/headroom-replay-verifier.d.ts +19 -0
  18. package/dist/evidence/headroom-replay-verifier.js +86 -0
  19. package/dist/memory/local-graph-memory-store.d.ts +75 -0
  20. package/dist/memory/local-graph-memory-store.js +570 -0
  21. package/dist/orchestration/dag.d.ts +22 -1
  22. package/dist/orchestration/evidence-gate.js +12 -0
  23. package/dist/orchestration/executor.js +111 -15
  24. package/dist/orchestration/loop-controller-headroom.d.ts +6 -0
  25. package/dist/orchestration/loop-controller-headroom.js +33 -0
  26. package/dist/orchestration/scheduler.d.ts +2 -0
  27. package/dist/orchestration/scheduler.js +3 -0
  28. package/dist/orchestration/task-graph.d.ts +17 -0
  29. package/dist/orchestration/task-graph.js +38 -0
  30. package/dist/providers/codex-cli-runner.js +17 -2
  31. package/dist/runtime/agent-runtime.d.ts +32 -3
  32. package/dist/runtime/agent-runtime.js +20 -7
  33. package/dist/runtime/authority-matrix.d.ts +23 -0
  34. package/dist/runtime/authority-matrix.js +171 -0
  35. package/dist/runtime/chat-advisory-runtime.js +3 -0
  36. package/dist/runtime/codex-cli-runtime.js +2 -0
  37. package/dist/runtime/codex-runtime.d.ts +4 -1
  38. package/dist/runtime/codex-runtime.js +34 -12
  39. package/dist/runtime/context-broker-converter.js +32 -2
  40. package/dist/runtime/context-broker.js +18 -0
  41. package/dist/runtime/contracts/evidence.d.ts +52 -0
  42. package/dist/runtime/contracts/evidence.js +138 -1
  43. package/dist/runtime/contracts/shared.d.ts +27 -0
  44. package/dist/runtime/data-retention-gate.d.ts +42 -0
  45. package/dist/runtime/data-retention-gate.js +123 -0
  46. package/dist/runtime/deepseek-runtime.d.ts +5 -1
  47. package/dist/runtime/deepseek-runtime.js +13 -7
  48. package/dist/runtime/external-cli-adapter.js +20 -7
  49. package/dist/runtime/freedomd-evidence-envelope.d.ts +57 -0
  50. package/dist/runtime/freedomd-evidence-envelope.js +110 -0
  51. package/dist/runtime/freedomd-exception.d.ts +32 -0
  52. package/dist/runtime/freedomd-exception.js +95 -0
  53. package/dist/runtime/freedomd-incidents.d.ts +23 -0
  54. package/dist/runtime/freedomd-incidents.js +103 -0
  55. package/dist/runtime/freedomd-policy.d.ts +35 -0
  56. package/dist/runtime/freedomd-policy.js +114 -0
  57. package/dist/runtime/freedomd-router.d.ts +66 -0
  58. package/dist/runtime/freedomd-router.js +433 -0
  59. package/dist/runtime/headroom-aware-loop-decision.d.ts +21 -0
  60. package/dist/runtime/headroom-aware-loop-decision.js +67 -0
  61. package/dist/runtime/headroom-loop-risk.d.ts +19 -0
  62. package/dist/runtime/headroom-loop-risk.js +43 -0
  63. package/dist/runtime/headroom-policy.d.ts +14 -1
  64. package/dist/runtime/headroom-policy.js +74 -12
  65. package/dist/runtime/kimi-api-runtime.d.ts +4 -1
  66. package/dist/runtime/kimi-api-runtime.js +35 -11
  67. package/dist/runtime/kimi-print-runtime.js +21 -0
  68. package/dist/runtime/kimi-wire-protocol-runtime.js +17 -1
  69. package/dist/runtime/local-llm-runtime.d.ts +5 -1
  70. package/dist/runtime/local-llm-runtime.js +14 -23
  71. package/dist/runtime/private-stderr.d.ts +13 -0
  72. package/dist/runtime/private-stderr.js +69 -0
  73. package/dist/runtime/prompt-envelope.d.ts +1 -1
  74. package/dist/runtime/provider-sovereignty.d.ts +81 -0
  75. package/dist/runtime/provider-sovereignty.js +285 -0
  76. package/dist/runtime/runtime-backed-task-runner.d.ts +1 -0
  77. package/dist/runtime/runtime-backed-task-runner.js +282 -10
  78. package/dist/runtime/runtime-bootstrap.d.ts +12 -0
  79. package/dist/runtime/runtime-bootstrap.js +54 -11
  80. package/dist/runtime/runtime-failure-classifier.d.ts +15 -0
  81. package/dist/runtime/runtime-failure-classifier.js +107 -0
  82. package/dist/runtime/runtime-health-probes.d.ts +30 -0
  83. package/dist/runtime/runtime-health-probes.js +102 -0
  84. package/dist/runtime/runtime-router.d.ts +6 -2
  85. package/dist/runtime/runtime-router.js +575 -53
  86. package/dist/runtime/structured-compaction.d.ts +107 -0
  87. package/dist/runtime/structured-compaction.js +414 -0
  88. package/dist/runtime/tool-dispatch-contracts.d.ts +7 -5
  89. package/dist/runtime/tool-dispatch-contracts.js +15 -4
  90. package/dist/runtime/tool-plane.d.ts +1 -1
  91. package/dist/runtime/tool-plane.js +49 -1
  92. package/dist/runtime/worker-manifest.js +1 -1
  93. package/dist/schema/evidence-bundle.schema.d.ts +8 -8
  94. package/dist/schema/proof-bundle.schema.d.ts +2 -2
  95. package/dist/util/hash.d.ts +2 -0
  96. package/dist/util/hash.js +13 -0
  97. package/dist/util/session.js +5 -4
  98. package/docs/2026-06-16/critical-issues.md +19 -0
  99. package/docs/2026-06-16/improvements.md +15 -0
  100. package/docs/2026-06-16/init-checklist.md +25 -0
  101. package/docs/2026-06-16/plan.md +20 -0
  102. package/docs/2026-06-17/critical-issues.md +19 -0
  103. package/docs/2026-06-17/improvements.md +15 -0
  104. package/docs/2026-06-17/init-checklist.md +25 -0
  105. package/docs/2026-06-17/plan.md +20 -0
  106. package/docs/ARCHITECTURE_ANALYSIS_CODEGRAPH.md +2 -1
  107. package/docs/GSTACK_MIGRATION.md +1 -1
  108. package/docs/algorithm-hardening-playbook.md +219 -0
  109. package/docs/claims.md +1 -1
  110. package/docs/getting-started.md +1 -1
  111. package/docs/native-root-runtime-hardening.md +42 -32
  112. package/docs/post-0793-hardening-roadmap.md +123 -0
  113. package/docs/provider-maturity.md +18 -16
  114. package/docs/versioning.md +3 -3
  115. package/docs/what-is-omk.md +1 -1
  116. package/package.json +8 -4
  117. package/readmeasset/.npmignore +2 -0
  118. package/readmeasset/ASSET_INDEX.md +2 -0
  119. package/readmeasset/ASSET_PROVENANCE.md +40 -20
  120. package/readmeasset/omk-adaptorch-ouroboros-supermemory.svg +1 -1
  121. package/readmeasset/omk-control-surfaces.svg +1 -1
  122. package/readmeasset/omk-core-loop.svg +1 -1
  123. package/readmeasset/omk-freedomd-control-plane.svg +59 -0
  124. package/readmeasset/omk-freedomd-control-plane.webp +0 -0
  125. package/readmeasset/omk-init-control-loop.svg +1 -1
  126. package/readmeasset/omk-logo-mark.svg +1 -1
  127. package/readmeasset/omk-parallel-subagents.svg +1 -1
  128. package/readmeasset/omk-release-assertions.svg +1 -1
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "crypto";
2
2
  import { statSync } from "fs";
3
+ import { sha256FileSync } from "../util/hash.js";
3
4
  import { mkdir, readFile, rename, rm, writeFile } from "fs/promises";
4
5
  import { dirname, resolve } from "path";
5
6
  import { loadMemorySettings, summarizeMemorySettings, usesLocalGraphBackend, } from "./memory-config.js";
@@ -21,9 +22,21 @@ export const ONTOLOGY = {
21
22
  "Command",
22
23
  "File",
23
24
  "Evidence",
25
+ "EvidenceRequirement",
26
+ "EvidenceObservation",
27
+ "Artifact",
28
+ "HeadroomDecision",
24
29
  "Provider",
25
30
  "ProviderRoute",
26
31
  "ProviderFallback",
32
+ "ProviderFreedomProfile",
33
+ "ProviderIncident",
34
+ "RetentionPolicy",
35
+ "JurisdictionPolicy",
36
+ "SovereigntyDecision",
37
+ "DegradedPlan",
38
+ "LocalFallback",
39
+ "EvidenceEnvelope",
27
40
  "AuditLink",
28
41
  "Constraint",
29
42
  "Question",
@@ -40,15 +53,25 @@ export const ONTOLOGY = {
40
53
  "HAS_TOPIC",
41
54
  "HAS_DECISION",
42
55
  "HAS_TASK",
56
+ "HAS_TURN",
43
57
  "HAS_RISK",
44
58
  "HAS_COMMAND",
45
59
  "HAS_FILE",
46
60
  "HAS_EVIDENCE",
61
+ "HAS_HEADROOM_DECISION",
47
62
  "USES_PROVIDER",
48
63
  "HAS_PROVIDER_ROUTE",
49
64
  "ROUTES_TO",
50
65
  "FALLS_BACK_TO",
51
66
  "HAS_PROVIDER_FALLBACK",
67
+ "HAS_SOVEREIGNTY_DECISION",
68
+ "BLOCKED_BY_PROVIDER_POLICY",
69
+ "DEGRADED_TO",
70
+ "HAS_LOCAL_FALLBACK",
71
+ "HAS_RETENTION_POLICY",
72
+ "HAS_JURISDICTION_POLICY",
73
+ "AFFECTED_BY_INCIDENT",
74
+ "EVIDENCE_ENVELOPE_STORED_AT",
52
75
  "HAS_AUDIT_LINK",
53
76
  "LINKS_TO",
54
77
  "HAS_CONSTRAINT",
@@ -60,6 +83,10 @@ export const ONTOLOGY = {
60
83
  "DEPENDS_ON",
61
84
  "BLOCKED_BY",
62
85
  "EVIDENCED_BY",
86
+ "DECLARES_EVIDENCE_REQUIREMENT",
87
+ "OBSERVED_EVIDENCE",
88
+ "SATISFIED_BY",
89
+ "STORED_AT",
63
90
  "TOUCHES_FILE",
64
91
  ],
65
92
  };
@@ -73,9 +100,21 @@ const GENERATED_TYPES = new Set([
73
100
  "Command",
74
101
  "File",
75
102
  "Evidence",
103
+ "EvidenceRequirement",
104
+ "EvidenceObservation",
105
+ "Artifact",
106
+ "HeadroomDecision",
76
107
  "Provider",
77
108
  "ProviderRoute",
78
109
  "ProviderFallback",
110
+ "ProviderFreedomProfile",
111
+ "ProviderIncident",
112
+ "RetentionPolicy",
113
+ "JurisdictionPolicy",
114
+ "SovereigntyDecision",
115
+ "DegradedPlan",
116
+ "LocalFallback",
117
+ "EvidenceEnvelope",
79
118
  "AuditLink",
80
119
  "Constraint",
81
120
  "Question",
@@ -88,6 +127,10 @@ const CANONICAL_NODE_TYPES = new Set([
88
127
  "Decision",
89
128
  "Risk",
90
129
  "Evidence",
130
+ "EvidenceRequirement",
131
+ "EvidenceObservation",
132
+ "Artifact",
133
+ "HeadroomDecision",
91
134
  "Goal",
92
135
  "Run",
93
136
  "Task",
@@ -96,6 +139,14 @@ const CANONICAL_NODE_TYPES = new Set([
96
139
  "Provider",
97
140
  "ProviderRoute",
98
141
  "ProviderFallback",
142
+ "ProviderFreedomProfile",
143
+ "ProviderIncident",
144
+ "RetentionPolicy",
145
+ "JurisdictionPolicy",
146
+ "SovereigntyDecision",
147
+ "DegradedPlan",
148
+ "LocalFallback",
149
+ "EvidenceEnvelope",
99
150
  "AuditLink",
100
151
  ]);
101
152
  const graphWriteQueues = new Map();
@@ -308,6 +359,516 @@ export class LocalGraphMemoryStore {
308
359
  await writeFile(`${mirrorDir}/commands.md`, `# Commands\n\n${renderNodes(byType("Command"))}`, "utf-8");
309
360
  await writeFile(`${mirrorDir}/risks.md`, `# Risks\n\n${renderNodes(byType("Risk"))}`, "utf-8");
310
361
  }
362
+ async materializeTurnAudit(input) {
363
+ await this.mutateState((state, now) => {
364
+ state.updatedAt = now;
365
+ state.project = { ...this.settings.project };
366
+ state.ontology = ONTOLOGY;
367
+ const runId = this.nodeId("Run", input.runId);
368
+ const turnId = this.nodeId("Task", `${input.runId}:${input.nodeId}`);
369
+ const providerName = input.provider ?? input.selectedRuntime?.split("-")[0] ?? "unknown";
370
+ const routeId = this.nodeId("ProviderRoute", `${input.runId}:${input.nodeId}:${input.selectedRuntime ?? providerName}`);
371
+ const evidenceId = this.nodeId("Evidence", `${input.runId}:${input.nodeId}:${input.evidenceArtifactPath ?? input.evidenceKind ?? "result"}`);
372
+ const providerId = this.nodeId("Provider", providerName);
373
+ const artifactId = input.evidenceArtifactPath
374
+ ? this.nodeId("Artifact", `${input.runId}:${input.evidenceArtifactPath}`)
375
+ : undefined;
376
+ const requirementEntries = (input.evidenceRequirements ?? [])
377
+ .filter((requirement) => requirement.required !== false)
378
+ .map((requirement) => ({
379
+ requirement,
380
+ id: this.nodeId("EvidenceRequirement", `${input.runId}:${input.nodeId}:${requirement.gate}:${requirement.ref ?? ""}`),
381
+ }));
382
+ const observationEntries = (input.evidenceObservations ?? [])
383
+ .map((observation, index) => ({
384
+ observation,
385
+ id: this.nodeId("Evidence", `${input.runId}:${input.nodeId}:observation:${index}:${observation.kind}:${observation.ref ?? observation.artifactPath ?? ""}`),
386
+ }));
387
+ const projectId = this.nodeId("Project", this.settings.project.key);
388
+ this.upsertNode(state, {
389
+ id: projectId,
390
+ type: "Project",
391
+ labels: ["OmkProject", "Project"],
392
+ label: this.settings.project.name,
393
+ summary: this.settings.project.root,
394
+ tags: ["project"],
395
+ properties: { key: this.settings.project.key, root: this.settings.project.root },
396
+ createdAt: now,
397
+ updatedAt: now,
398
+ });
399
+ this.upsertNode(state, {
400
+ id: runId,
401
+ type: "Run",
402
+ labels: ["OmkRun", "Run"],
403
+ label: input.runId,
404
+ summary: `Run ${input.runId}`,
405
+ tags: ["run", "audit"],
406
+ properties: { key: input.runId, runId: input.runId, projectKey: this.settings.project.key },
407
+ createdAt: now,
408
+ updatedAt: now,
409
+ });
410
+ this.upsertNode(state, {
411
+ id: turnId,
412
+ type: "Task",
413
+ labels: ["OmkTurn", "Task"],
414
+ label: input.nodeId,
415
+ summary: `Turn ${input.nodeId}`,
416
+ tags: ["turn", "audit"],
417
+ properties: { key: `${input.runId}:${input.nodeId}`, runId: input.runId, nodeId: input.nodeId },
418
+ createdAt: now,
419
+ updatedAt: now,
420
+ });
421
+ this.upsertNode(state, {
422
+ id: routeId,
423
+ type: "ProviderRoute",
424
+ labels: ["OmkProviderRoute", "ProviderRoute"],
425
+ label: input.selectedRuntime ?? input.provider ?? "unknown-runtime",
426
+ summary: `Selected runtime: ${input.selectedRuntime ?? input.provider ?? "unknown"}`,
427
+ tags: ["provider-route", "audit"],
428
+ properties: {
429
+ key: `${input.runId}:${input.nodeId}:route`,
430
+ runId: input.runId,
431
+ nodeId: input.nodeId,
432
+ provider: providerName,
433
+ selectedRuntime: input.selectedRuntime ?? "unknown",
434
+ fallbackChain: (input.fallbackChain ?? []).join(","),
435
+ },
436
+ createdAt: now,
437
+ updatedAt: now,
438
+ });
439
+ this.upsertNode(state, {
440
+ id: providerId,
441
+ type: "Provider",
442
+ labels: ["OmkProvider", "Provider"],
443
+ label: providerName,
444
+ summary: `Provider ${providerName}`,
445
+ tags: ["provider", "audit"],
446
+ properties: { key: providerName, provider: providerName },
447
+ createdAt: now,
448
+ updatedAt: now,
449
+ });
450
+ this.upsertNode(state, {
451
+ id: evidenceId,
452
+ type: "Evidence",
453
+ labels: ["OmkEvidence", "Evidence", "EvidenceObservation"],
454
+ label: input.evidenceKind ?? "turn-result",
455
+ summary: input.evidenceArtifactPath ?? "turn result artifact",
456
+ tags: ["evidence", "audit", "observation"],
457
+ properties: {
458
+ key: `${input.runId}:${input.nodeId}:evidence`,
459
+ runId: input.runId,
460
+ nodeId: input.nodeId,
461
+ kind: input.evidenceKind ?? "turn-result",
462
+ artifactRef: input.evidenceArtifactPath ?? "",
463
+ sha256: input.evidenceHash ?? "",
464
+ },
465
+ createdAt: now,
466
+ updatedAt: now,
467
+ });
468
+ if (artifactId && input.evidenceArtifactPath) {
469
+ const artifactPath = input.evidenceArtifactPath;
470
+ this.upsertNode(state, {
471
+ id: artifactId,
472
+ type: "Artifact",
473
+ labels: ["OmkArtifact", "Artifact"],
474
+ label: artifactPath,
475
+ summary: artifactPath,
476
+ tags: ["artifact", "audit"],
477
+ properties: {
478
+ key: `${input.runId}:${artifactPath}`,
479
+ runId: input.runId,
480
+ path: artifactPath,
481
+ sha256: input.evidenceHash ?? "",
482
+ },
483
+ createdAt: now,
484
+ updatedAt: now,
485
+ });
486
+ }
487
+ for (const { requirement, id } of requirementEntries) {
488
+ this.upsertNode(state, {
489
+ id,
490
+ type: "EvidenceRequirement",
491
+ labels: ["OmkEvidenceRequirement", "EvidenceRequirement"],
492
+ label: requirement.gate,
493
+ summary: requirement.ref ?? requirement.gate,
494
+ tags: ["evidence", "audit", "requirement"],
495
+ properties: {
496
+ key: `${input.runId}:${input.nodeId}:requirement:${requirement.gate}:${requirement.ref ?? ""}`,
497
+ runId: input.runId,
498
+ nodeId: input.nodeId,
499
+ gate: requirement.gate,
500
+ ref: requirement.ref ?? "",
501
+ required: requirement.required !== false,
502
+ },
503
+ createdAt: now,
504
+ updatedAt: now,
505
+ });
506
+ }
507
+ for (const { observation, id } of observationEntries) {
508
+ this.upsertNode(state, {
509
+ id,
510
+ type: "Evidence",
511
+ labels: ["OmkEvidence", "Evidence", "EvidenceObservation"],
512
+ label: observation.kind,
513
+ summary: observation.ref ?? observation.artifactPath ?? observation.kind,
514
+ tags: ["evidence", "audit", "observation"],
515
+ properties: {
516
+ key: `${input.runId}:${input.nodeId}:observation:${observation.kind}:${observation.ref ?? observation.artifactPath ?? ""}`,
517
+ runId: input.runId,
518
+ nodeId: input.nodeId,
519
+ kind: observation.kind,
520
+ source: observation.source,
521
+ ref: observation.ref ?? "",
522
+ artifactRef: observation.artifactPath ?? "",
523
+ confidence: observation.confidence ?? 0,
524
+ replayable: observation.replayable !== false,
525
+ redacted: observation.redacted !== false,
526
+ },
527
+ createdAt: now,
528
+ updatedAt: now,
529
+ });
530
+ }
531
+ this.upsertEdge(state, projectId, runId, "HAS_RUN", now);
532
+ this.upsertEdge(state, runId, turnId, "HAS_TASK", now);
533
+ this.upsertEdge(state, runId, turnId, "HAS_TURN", now);
534
+ this.upsertEdge(state, turnId, routeId, "HAS_PROVIDER_ROUTE", now);
535
+ this.upsertEdge(state, routeId, providerId, "ROUTES_TO", now);
536
+ this.upsertEdge(state, turnId, evidenceId, "OBSERVED_EVIDENCE", now);
537
+ this.upsertEdge(state, routeId, evidenceId, "EVIDENCED_BY", now);
538
+ if (artifactId)
539
+ this.upsertEdge(state, evidenceId, artifactId, "STORED_AT", now);
540
+ for (const { id } of requirementEntries) {
541
+ this.upsertEdge(state, turnId, id, "DECLARES_EVIDENCE_REQUIREMENT", now);
542
+ }
543
+ for (const { id, observation } of observationEntries) {
544
+ this.upsertEdge(state, turnId, id, "OBSERVED_EVIDENCE", now);
545
+ if (observation.artifactPath && artifactId && observation.artifactPath === input.evidenceArtifactPath) {
546
+ this.upsertEdge(state, id, artifactId, "STORED_AT", now);
547
+ }
548
+ for (const { id: requirementId, requirement } of requirementEntries) {
549
+ if (evidenceObservationSatisfiesRequirement(requirement.gate, observation.kind)) {
550
+ this.upsertEdge(state, requirementId, id, "SATISFIED_BY", now);
551
+ }
552
+ }
553
+ }
554
+ });
555
+ }
556
+ async materializeHeadroomDecision(input) {
557
+ await this.mutateState((state, now) => {
558
+ state.updatedAt = now;
559
+ state.project = { ...this.settings.project };
560
+ state.ontology = ONTOLOGY;
561
+ const projectId = this.nodeId("Project", this.settings.project.key);
562
+ const runId = this.nodeId("Run", input.runId);
563
+ const taskId = this.nodeId("Task", `${input.runId}:${input.nodeId}`);
564
+ const decisionId = this.nodeId("HeadroomDecision", `${input.runId}:${input.nodeId}`);
565
+ const artifactId = input.artifactRef
566
+ ? this.nodeId("Artifact", `${input.runId}:${input.artifactRef}`)
567
+ : undefined;
568
+ const attempted = input.metadata.attempted === true;
569
+ const applied = input.metadata.applied === true;
570
+ const reason = input.metadata.reason ?? "headroom decision";
571
+ this.upsertNode(state, {
572
+ id: projectId,
573
+ type: "Project",
574
+ labels: ["OmkProject", "Project"],
575
+ label: this.settings.project.name,
576
+ summary: this.settings.project.root,
577
+ tags: ["project"],
578
+ properties: { key: this.settings.project.key, root: this.settings.project.root },
579
+ createdAt: now,
580
+ updatedAt: now,
581
+ });
582
+ this.upsertNode(state, {
583
+ id: runId,
584
+ type: "Run",
585
+ labels: ["OmkRun", "Run"],
586
+ label: input.runId,
587
+ summary: `Run ${input.runId}`,
588
+ tags: ["run", "audit"],
589
+ properties: { key: input.runId, runId: input.runId, projectKey: this.settings.project.key },
590
+ createdAt: now,
591
+ updatedAt: now,
592
+ });
593
+ this.upsertNode(state, {
594
+ id: taskId,
595
+ type: "Task",
596
+ labels: ["OmkTurn", "Task"],
597
+ label: input.nodeId,
598
+ summary: `Turn ${input.nodeId}`,
599
+ tags: ["turn", "audit"],
600
+ properties: { key: `${input.runId}:${input.nodeId}`, runId: input.runId, nodeId: input.nodeId },
601
+ createdAt: now,
602
+ updatedAt: now,
603
+ });
604
+ this.upsertNode(state, {
605
+ id: decisionId,
606
+ type: "HeadroomDecision",
607
+ labels: ["OmkHeadroomDecision", "HeadroomDecision"],
608
+ label: `${input.nodeId}:headroom`,
609
+ summary: reason,
610
+ tags: ["headroom", "compaction", "audit"],
611
+ properties: {
612
+ key: `${input.runId}:${input.nodeId}:headroom`,
613
+ runId: input.runId,
614
+ nodeId: input.nodeId,
615
+ attempted,
616
+ backend: input.metadata.backend ?? "none",
617
+ compacted: input.metadata.compacted === true,
618
+ compactedTextProduced: input.metadata.compactedTextProduced === true,
619
+ validated: input.metadata.validated === true,
620
+ applied,
621
+ beforeTokens: input.metadata.beforeTokens ?? 0,
622
+ afterTokens: input.metadata.afterTokens ?? 0,
623
+ utilization: input.metadata.utilization ?? 0,
624
+ threshold: input.metadata.threshold ?? 0,
625
+ contract: input.metadata.contract ?? "unknown",
626
+ reason,
627
+ missingSections: (input.metadata.missingSections ?? []).join(","),
628
+ qualityScore: input.metadata.qualityScore ?? 0,
629
+ compressionRatio: input.metadata.compressionRatio ?? 0,
630
+ },
631
+ createdAt: now,
632
+ updatedAt: now,
633
+ });
634
+ if (artifactId && input.artifactRef) {
635
+ const artifactPath = resolve(this.settings.project.root, input.artifactRef);
636
+ let sha256 = null;
637
+ let sizeBytes = null;
638
+ let exists = false;
639
+ try {
640
+ const stats = statSync(artifactPath);
641
+ sizeBytes = stats.size;
642
+ sha256 = sha256FileSync(artifactPath) ?? null;
643
+ exists = true;
644
+ }
645
+ catch {
646
+ sha256 = null;
647
+ sizeBytes = null;
648
+ exists = false;
649
+ }
650
+ this.upsertNode(state, {
651
+ id: artifactId,
652
+ type: "Artifact",
653
+ labels: ["OmkArtifact", "Artifact"],
654
+ label: input.artifactRef,
655
+ summary: input.artifactRef,
656
+ tags: ["artifact", "headroom", "audit"],
657
+ properties: {
658
+ key: `${input.runId}:${input.artifactRef}`,
659
+ runId: input.runId,
660
+ path: input.artifactRef,
661
+ kind: "headroom-decision",
662
+ sha256,
663
+ sizeBytes,
664
+ exists,
665
+ },
666
+ createdAt: now,
667
+ updatedAt: now,
668
+ });
669
+ if (!exists) {
670
+ const missingArtifactRiskId = this.nodeId("Risk", `${input.runId}:${input.nodeId}:missing-headroom-artifact`);
671
+ this.upsertNode(state, {
672
+ id: missingArtifactRiskId,
673
+ type: "Risk",
674
+ labels: ["OmkRisk", "Risk"],
675
+ label: "missing-headroom-artifact",
676
+ summary: "headroom decision artifactRef did not resolve",
677
+ tags: ["risk", "headroom", "artifact"],
678
+ properties: {
679
+ key: `${input.runId}:${input.nodeId}:missing-headroom-artifact`,
680
+ runId: input.runId,
681
+ nodeId: input.nodeId,
682
+ kind: "missing-headroom-artifact",
683
+ artifactRef: input.artifactRef,
684
+ },
685
+ createdAt: now,
686
+ updatedAt: now,
687
+ });
688
+ this.upsertEdge(state, decisionId, missingArtifactRiskId, "HAS_RISK", now);
689
+ }
690
+ }
691
+ this.upsertEdge(state, projectId, runId, "HAS_RUN", now);
692
+ this.upsertEdge(state, runId, taskId, "HAS_TASK", now);
693
+ this.upsertEdge(state, taskId, decisionId, "HAS_HEADROOM_DECISION", now);
694
+ if (artifactId)
695
+ this.upsertEdge(state, decisionId, artifactId, "STORED_AT", now);
696
+ if (attempted && !applied) {
697
+ const riskId = this.nodeId("Risk", `${input.runId}:${input.nodeId}:headroom`);
698
+ this.upsertNode(state, {
699
+ id: riskId,
700
+ type: "Risk",
701
+ labels: ["OmkRisk", "Risk"],
702
+ label: "headroom-compaction-not-applied",
703
+ summary: reason,
704
+ tags: ["risk", "headroom", "compaction"],
705
+ properties: {
706
+ key: `${input.runId}:${input.nodeId}:headroom-risk`,
707
+ runId: input.runId,
708
+ nodeId: input.nodeId,
709
+ kind: "headroom-compaction-not-applied",
710
+ reason,
711
+ missingSections: (input.metadata.missingSections ?? []).join(","),
712
+ },
713
+ createdAt: now,
714
+ updatedAt: now,
715
+ });
716
+ this.upsertEdge(state, taskId, riskId, "HAS_RISK", now);
717
+ }
718
+ });
719
+ }
720
+ async materializeFreedomdSovereignty(input) {
721
+ await this.mutateState((state, now) => {
722
+ state.updatedAt = now;
723
+ state.ontology = ONTOLOGY;
724
+ const runNodeId = this.nodeId("Run", input.runId);
725
+ const taskId = this.nodeId("Task", `${input.runId}:${input.nodeId}`);
726
+ const decisionId = this.nodeId("SovereigntyDecision", `${input.runId}:${input.nodeId}`);
727
+ const providerId = this.nodeId("Provider", `${input.providerId}:${input.runtimeMode}`);
728
+ this.upsertNode(state, {
729
+ id: runNodeId,
730
+ type: "Run",
731
+ labels: ["OmkRun", "Run"],
732
+ label: input.runId,
733
+ summary: `Run ${input.runId}`,
734
+ tags: ["run", "audit", "freedomd"],
735
+ properties: { key: input.runId, runId: input.runId },
736
+ createdAt: now,
737
+ updatedAt: now,
738
+ });
739
+ this.upsertNode(state, {
740
+ id: taskId,
741
+ type: "Task",
742
+ labels: ["OmkTurn", "Task"],
743
+ label: input.nodeId,
744
+ summary: `Turn ${input.nodeId}`,
745
+ tags: ["turn", "audit", "freedomd"],
746
+ properties: { key: `${input.runId}:${input.nodeId}`, runId: input.runId, nodeId: input.nodeId },
747
+ createdAt: now,
748
+ updatedAt: now,
749
+ });
750
+ this.upsertNode(state, {
751
+ id: providerId,
752
+ type: "Provider",
753
+ labels: ["OmkProvider", "Provider"],
754
+ label: `${input.providerId}:${input.runtimeMode}`,
755
+ summary: `Provider ${input.providerId} (${input.runtimeMode})`,
756
+ tags: ["provider", "freedomd"],
757
+ properties: { key: `${input.providerId}:${input.runtimeMode}`, providerId: input.providerId, runtimeMode: input.runtimeMode },
758
+ createdAt: now,
759
+ updatedAt: now,
760
+ });
761
+ this.upsertNode(state, {
762
+ id: decisionId,
763
+ type: "SovereigntyDecision",
764
+ labels: ["OmkSovereigntyDecision", "SovereigntyDecision"],
765
+ label: `${input.nodeId}:sovereignty`,
766
+ summary: input.sovereignty.reason,
767
+ tags: ["sovereignty", "freedomd", "audit"],
768
+ properties: {
769
+ key: `${input.runId}:${input.nodeId}:sovereignty`,
770
+ runId: input.runId,
771
+ nodeId: input.nodeId,
772
+ mode: input.sovereignty.mode,
773
+ dataBoundary: input.sovereignty.dataBoundary,
774
+ retentionDecision: input.sovereignty.retentionDecision,
775
+ jurisdictionDecision: input.sovereignty.jurisdictionDecision,
776
+ providerCutoffRisk: input.sovereignty.providerCutoffRisk,
777
+ localFallbackAvailable: input.sovereignty.localFallbackAvailable,
778
+ reason: input.sovereignty.reason,
779
+ },
780
+ createdAt: now,
781
+ updatedAt: now,
782
+ });
783
+ this.upsertEdge(state, runNodeId, taskId, "HAS_TASK", now);
784
+ this.upsertEdge(state, taskId, decisionId, "HAS_SOVEREIGNTY_DECISION", now);
785
+ this.upsertEdge(state, taskId, providerId, "USES_PROVIDER", now);
786
+ if (input.degradedMode) {
787
+ const degradedId = this.nodeId("DegradedPlan", `${input.runId}:${input.nodeId}`);
788
+ this.upsertNode(state, {
789
+ id: degradedId,
790
+ type: "DegradedPlan",
791
+ labels: ["OmkDegradedPlan", "DegradedPlan"],
792
+ label: input.degradedMode,
793
+ summary: `Degraded to ${input.degradedMode}`,
794
+ tags: ["degraded", "freedomd"],
795
+ properties: { key: `${input.runId}:${input.nodeId}:degraded`, runId: input.runId, nodeId: input.nodeId, mode: input.degradedMode },
796
+ createdAt: now,
797
+ updatedAt: now,
798
+ });
799
+ this.upsertEdge(state, taskId, degradedId, "DEGRADED_TO", now);
800
+ }
801
+ if (input.incident) {
802
+ const incidentId = this.nodeId("ProviderIncident", `${input.runId}:${input.nodeId}:${input.providerId}`);
803
+ this.upsertNode(state, {
804
+ id: incidentId,
805
+ type: "ProviderIncident",
806
+ labels: ["OmkProviderIncident", "ProviderIncident"],
807
+ label: input.incident.kind,
808
+ summary: input.incident.reason,
809
+ tags: ["incident", "freedomd", input.incident.severity],
810
+ properties: {
811
+ key: `${input.runId}:${input.nodeId}:${input.providerId}:incident`,
812
+ runId: input.runId,
813
+ nodeId: input.nodeId,
814
+ providerId: input.providerId,
815
+ kind: input.incident.kind,
816
+ severity: input.incident.severity,
817
+ reason: input.incident.reason,
818
+ },
819
+ createdAt: now,
820
+ updatedAt: now,
821
+ });
822
+ this.upsertEdge(state, decisionId, incidentId, "AFFECTED_BY_INCIDENT", now);
823
+ }
824
+ });
825
+ }
826
+ async materializeFreedomdEvidenceEnvelope(input) {
827
+ await this.mutateState((state, now) => {
828
+ state.updatedAt = now;
829
+ state.ontology = ONTOLOGY;
830
+ const taskId = this.nodeId("Task", `${input.runId}:${input.nodeId}`);
831
+ const envelopeId = this.nodeId("EvidenceEnvelope", `${input.runId}:${input.nodeId}`);
832
+ const artifactId = this.nodeId("Artifact", `${input.runId}:${input.envelopePath}`);
833
+ this.upsertNode(state, {
834
+ id: envelopeId,
835
+ type: "EvidenceEnvelope",
836
+ labels: ["OmkEvidenceEnvelope", "EvidenceEnvelope"],
837
+ label: `${input.nodeId}:evidence-envelope`,
838
+ summary: "Freedomd local-first evidence envelope",
839
+ tags: ["evidence", "freedomd", "audit"],
840
+ properties: {
841
+ key: `${input.runId}:${input.nodeId}:evidence-envelope`,
842
+ runId: input.runId,
843
+ nodeId: input.nodeId,
844
+ path: input.envelopePath,
845
+ },
846
+ createdAt: now,
847
+ updatedAt: now,
848
+ });
849
+ this.upsertNode(state, {
850
+ id: artifactId,
851
+ type: "Artifact",
852
+ labels: ["OmkArtifact", "Artifact"],
853
+ label: input.envelopePath,
854
+ summary: input.envelopePath,
855
+ tags: ["artifact", "evidence", "freedomd"],
856
+ properties: {
857
+ key: `${input.runId}:${input.envelopePath}`,
858
+ runId: input.runId,
859
+ path: input.envelopePath,
860
+ kind: "freedomd-evidence-envelope",
861
+ sha256: input.sha256 ?? null,
862
+ sizeBytes: input.sizeBytes ?? null,
863
+ exists: input.exists ?? false,
864
+ },
865
+ createdAt: now,
866
+ updatedAt: now,
867
+ });
868
+ this.upsertEdge(state, taskId, envelopeId, "HAS_EVIDENCE", now);
869
+ this.upsertEdge(state, envelopeId, artifactId, "EVIDENCE_ENVELOPE_STORED_AT", now);
870
+ });
871
+ }
311
872
  async append(path, content) {
312
873
  await this.mutateState((state, now) => {
313
874
  const existing = this.readFromState(state, path);
@@ -1300,6 +1861,15 @@ function readNumberArg(query, name) {
1300
1861
  const match = query.match(new RegExp(`${name}\\s*:\\s*(\\d+)`, "i"));
1301
1862
  return match ? Number.parseInt(match[1], 10) : undefined;
1302
1863
  }
1864
+ function evidenceObservationSatisfiesRequirement(requirementGate, observationKind) {
1865
+ if (observationKind === requirementGate)
1866
+ return true;
1867
+ if (requirementGate === "test-pass" && observationKind === "command-pass")
1868
+ return true;
1869
+ if (requirementGate === "file-exists" && observationKind === "artifact")
1870
+ return true;
1871
+ return false;
1872
+ }
1303
1873
  function hash(value) {
1304
1874
  return createHash("sha256").update(value).digest("hex");
1305
1875
  }
@@ -1,7 +1,7 @@
1
1
  import type { DeepSeekModelTier, DeepSeekParticipation, ProviderId } from "../providers/types.js";
2
2
  export type TaskStatus = "pending" | "running" | "done" | "failed" | "blocked" | "skipped";
3
3
  export type DagContextBudget = "tiny" | "small" | "normal";
4
- export type DagOutputGate = "file-exists" | "test-pass" | "review-pass" | "command-pass" | "summary" | "none";
4
+ export type DagOutputGate = "file-exists" | "test-pass" | "review-pass" | "command-pass" | "summary" | "artifact" | "diff" | "none";
5
5
  export interface DagNodeInput {
6
6
  name: string;
7
7
  ref: string;
@@ -39,6 +39,9 @@ export interface DagNodeRouting {
39
39
  approvalPolicy?: string;
40
40
  executionPrompt?: string;
41
41
  promptMode?: string;
42
+ promptHash?: string;
43
+ promptPayloadRef?: string;
44
+ promptPayloadPrivate?: boolean;
42
45
  runtimeSidecar?: unknown;
43
46
  needsIntegration?: boolean;
44
47
  /**
@@ -73,6 +76,24 @@ export interface DagNodeRouting {
73
76
  };
74
77
  reason: string;
75
78
  }>;
79
+ riskTrace?: {
80
+ risk?: string;
81
+ confidence?: number;
82
+ matchedSignal?: string;
83
+ readOnlyOverride?: boolean;
84
+ positiveSignals?: readonly string[];
85
+ negativeScopes?: readonly string[];
86
+ requestedOps?: readonly string[];
87
+ excludedOps?: readonly string[];
88
+ };
89
+ /** Freedomd sovereignty metadata for provider-independent routing. */
90
+ freedomd?: {
91
+ dataBoundary?: "public" | "internal" | "customer" | "secret";
92
+ preferredProvider?: string;
93
+ allowProviderExceptions?: boolean;
94
+ degradedMode?: string;
95
+ sovereigntyReason?: string;
96
+ };
76
97
  replanHint?: {
77
98
  criterionId?: string;
78
99
  artifactRef?: string;