magi-ai 0.1.0

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 (300) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +377 -0
  3. package/README.md +377 -0
  4. package/dist/bin/magi-benchmark.d.ts +14 -0
  5. package/dist/bin/magi-benchmark.js +93 -0
  6. package/dist/bin/magi-mcp.d.ts +8 -0
  7. package/dist/bin/magi-mcp.js +28 -0
  8. package/dist/bin/magi.d.ts +2 -0
  9. package/dist/bin/magi.js +634 -0
  10. package/dist/src/adapters/base.d.ts +34 -0
  11. package/dist/src/adapters/base.js +149 -0
  12. package/dist/src/adapters/claude.d.ts +29 -0
  13. package/dist/src/adapters/claude.js +65 -0
  14. package/dist/src/adapters/codex.d.ts +21 -0
  15. package/dist/src/adapters/codex.js +41 -0
  16. package/dist/src/adapters/gemini.d.ts +18 -0
  17. package/dist/src/adapters/gemini.js +31 -0
  18. package/dist/src/adapters/registry.d.ts +19 -0
  19. package/dist/src/adapters/registry.js +59 -0
  20. package/dist/src/audit/hash-chain.d.ts +21 -0
  21. package/dist/src/audit/hash-chain.js +70 -0
  22. package/dist/src/audit/types.d.ts +25 -0
  23. package/dist/src/audit/types.js +1 -0
  24. package/dist/src/audit/writer.d.ts +18 -0
  25. package/dist/src/audit/writer.js +100 -0
  26. package/dist/src/benchmark/golden-tasks.d.ts +9 -0
  27. package/dist/src/benchmark/golden-tasks.js +476 -0
  28. package/dist/src/benchmark/reporter.d.ts +5 -0
  29. package/dist/src/benchmark/reporter.js +107 -0
  30. package/dist/src/benchmark/runner.d.ts +30 -0
  31. package/dist/src/benchmark/runner.js +224 -0
  32. package/dist/src/benchmark/scorer.d.ts +12 -0
  33. package/dist/src/benchmark/scorer.js +124 -0
  34. package/dist/src/benchmark/types.d.ts +54 -0
  35. package/dist/src/benchmark/types.js +1 -0
  36. package/dist/src/cache/deliberation-cache.d.ts +49 -0
  37. package/dist/src/cache/deliberation-cache.js +127 -0
  38. package/dist/src/cli/commands/config-cmd.d.ts +11 -0
  39. package/dist/src/cli/commands/config-cmd.js +190 -0
  40. package/dist/src/cli/commands/demo.d.ts +12 -0
  41. package/dist/src/cli/commands/demo.js +66 -0
  42. package/dist/src/cli/commands/setup.d.ts +7 -0
  43. package/dist/src/cli/commands/setup.js +182 -0
  44. package/dist/src/cli/i18n.d.ts +89 -0
  45. package/dist/src/cli/i18n.js +176 -0
  46. package/dist/src/cli/interactive-select.d.ts +27 -0
  47. package/dist/src/cli/interactive-select.js +130 -0
  48. package/dist/src/cli/tui-setup.d.ts +24 -0
  49. package/dist/src/cli/tui-setup.js +42 -0
  50. package/dist/src/config/cli-detector.d.ts +37 -0
  51. package/dist/src/config/cli-detector.js +99 -0
  52. package/dist/src/config/user-config.d.ts +81 -0
  53. package/dist/src/config/user-config.js +134 -0
  54. package/dist/src/context/auto-collector.d.ts +43 -0
  55. package/dist/src/context/auto-collector.js +337 -0
  56. package/dist/src/context/manager.d.ts +35 -0
  57. package/dist/src/context/manager.js +162 -0
  58. package/dist/src/context/serializer.d.ts +20 -0
  59. package/dist/src/context/serializer.js +52 -0
  60. package/dist/src/demo/recorded-deliberation.d.ts +13 -0
  61. package/dist/src/demo/recorded-deliberation.js +277 -0
  62. package/dist/src/engine/angel-detector.d.ts +83 -0
  63. package/dist/src/engine/angel-detector.js +334 -0
  64. package/dist/src/engine/at-field.d.ts +40 -0
  65. package/dist/src/engine/at-field.js +195 -0
  66. package/dist/src/engine/berserk-orchestrator.d.ts +66 -0
  67. package/dist/src/engine/berserk-orchestrator.js +378 -0
  68. package/dist/src/engine/change-metrics.d.ts +56 -0
  69. package/dist/src/engine/change-metrics.js +214 -0
  70. package/dist/src/engine/consensus.d.ts +20 -0
  71. package/dist/src/engine/consensus.js +146 -0
  72. package/dist/src/engine/dead-sea-scrolls.d.ts +132 -0
  73. package/dist/src/engine/dead-sea-scrolls.js +610 -0
  74. package/dist/src/engine/drift-detector.d.ts +39 -0
  75. package/dist/src/engine/drift-detector.js +225 -0
  76. package/dist/src/engine/dummy-plug.d.ts +44 -0
  77. package/dist/src/engine/dummy-plug.js +190 -0
  78. package/dist/src/engine/engram-manager.d.ts +55 -0
  79. package/dist/src/engine/engram-manager.js +306 -0
  80. package/dist/src/engine/events.d.ts +130 -0
  81. package/dist/src/engine/events.js +44 -0
  82. package/dist/src/engine/gospel.d.ts +30 -0
  83. package/dist/src/engine/gospel.js +129 -0
  84. package/dist/src/engine/hallucination-detector.d.ts +33 -0
  85. package/dist/src/engine/hallucination-detector.js +215 -0
  86. package/dist/src/engine/human-resolver.d.ts +19 -0
  87. package/dist/src/engine/human-resolver.js +89 -0
  88. package/dist/src/engine/instrumentality.d.ts +64 -0
  89. package/dist/src/engine/instrumentality.js +297 -0
  90. package/dist/src/engine/iruel-battle.d.ts +79 -0
  91. package/dist/src/engine/iruel-battle.js +319 -0
  92. package/dist/src/engine/kernel/deliberation-kernel.d.ts +12 -0
  93. package/dist/src/engine/kernel/deliberation-kernel.js +303 -0
  94. package/dist/src/engine/kernel/index.d.ts +8 -0
  95. package/dist/src/engine/kernel/index.js +7 -0
  96. package/dist/src/engine/kernel/phase-runner.d.ts +10 -0
  97. package/dist/src/engine/kernel/phase-runner.js +155 -0
  98. package/dist/src/engine/kernel/post-processor.d.ts +17 -0
  99. package/dist/src/engine/kernel/post-processor.js +131 -0
  100. package/dist/src/engine/kernel/types.d.ts +107 -0
  101. package/dist/src/engine/kernel/types.js +1 -0
  102. package/dist/src/engine/kernel/unit-executor.d.ts +6 -0
  103. package/dist/src/engine/kernel/unit-executor.js +132 -0
  104. package/dist/src/engine/lcl-manager.d.ts +44 -0
  105. package/dist/src/engine/lcl-manager.js +143 -0
  106. package/dist/src/engine/middleware/cache.d.ts +7 -0
  107. package/dist/src/engine/middleware/cache.js +29 -0
  108. package/dist/src/engine/middleware/chain.d.ts +18 -0
  109. package/dist/src/engine/middleware/chain.js +45 -0
  110. package/dist/src/engine/middleware/firewall.d.ts +8 -0
  111. package/dist/src/engine/middleware/firewall.js +24 -0
  112. package/dist/src/engine/middleware/index.d.ts +4 -0
  113. package/dist/src/engine/middleware/index.js +3 -0
  114. package/dist/src/engine/middleware/types.d.ts +43 -0
  115. package/dist/src/engine/middleware/types.js +1 -0
  116. package/dist/src/engine/nebuchadnezzar-key.d.ts +61 -0
  117. package/dist/src/engine/nebuchadnezzar-key.js +203 -0
  118. package/dist/src/engine/neon-genesis.d.ts +52 -0
  119. package/dist/src/engine/neon-genesis.js +203 -0
  120. package/dist/src/engine/objective-judge.d.ts +53 -0
  121. package/dist/src/engine/objective-judge.js +214 -0
  122. package/dist/src/engine/offline-mode.d.ts +18 -0
  123. package/dist/src/engine/offline-mode.js +46 -0
  124. package/dist/src/engine/orchestrator.d.ts +79 -0
  125. package/dist/src/engine/orchestrator.js +58 -0
  126. package/dist/src/engine/secret-cipher.d.ts +26 -0
  127. package/dist/src/engine/secret-cipher.js +114 -0
  128. package/dist/src/engine/seele-council.d.ts +90 -0
  129. package/dist/src/engine/seele-council.js +482 -0
  130. package/dist/src/engine/self-destruct.d.ts +61 -0
  131. package/dist/src/engine/self-destruct.js +231 -0
  132. package/dist/src/engine/self-evolution.d.ts +64 -0
  133. package/dist/src/engine/self-evolution.js +368 -0
  134. package/dist/src/engine/sync-rate.d.ts +45 -0
  135. package/dist/src/engine/sync-rate.js +151 -0
  136. package/dist/src/engine/type666-firewall.d.ts +76 -0
  137. package/dist/src/engine/type666-firewall.js +343 -0
  138. package/dist/src/engine/umbilical-cable.d.ts +41 -0
  139. package/dist/src/engine/umbilical-cable.js +192 -0
  140. package/dist/src/index.d.ts +106 -0
  141. package/dist/src/index.js +426 -0
  142. package/dist/src/mcp/server.d.ts +38 -0
  143. package/dist/src/mcp/server.js +196 -0
  144. package/dist/src/metrics/token-tracker.d.ts +38 -0
  145. package/dist/src/metrics/token-tracker.js +112 -0
  146. package/dist/src/parsers/json-extractor.d.ts +9 -0
  147. package/dist/src/parsers/json-extractor.js +239 -0
  148. package/dist/src/parsers/opinion-schema.d.ts +81 -0
  149. package/dist/src/parsers/opinion-schema.js +147 -0
  150. package/dist/src/parsers/unstructured-parser.d.ts +20 -0
  151. package/dist/src/parsers/unstructured-parser.js +122 -0
  152. package/dist/src/pipelines/architecture.d.ts +10 -0
  153. package/dist/src/pipelines/architecture.js +9 -0
  154. package/dist/src/pipelines/bug-analysis.d.ts +9 -0
  155. package/dist/src/pipelines/bug-analysis.js +8 -0
  156. package/dist/src/pipelines/code-review.d.ts +10 -0
  157. package/dist/src/pipelines/code-review.js +30 -0
  158. package/dist/src/pipelines/custom.d.ts +14 -0
  159. package/dist/src/pipelines/custom.js +29 -0
  160. package/dist/src/pipelines/registry.d.ts +9 -0
  161. package/dist/src/pipelines/registry.js +20 -0
  162. package/dist/src/prompts/personas.d.ts +6 -0
  163. package/dist/src/prompts/personas.js +44 -0
  164. package/dist/src/prompts/schemas.d.ts +4 -0
  165. package/dist/src/prompts/schemas.js +24 -0
  166. package/dist/src/prompts/templates.d.ts +6 -0
  167. package/dist/src/prompts/templates.js +91 -0
  168. package/dist/src/repl/accessibility.d.ts +23 -0
  169. package/dist/src/repl/accessibility.js +46 -0
  170. package/dist/src/repl/banner.d.ts +4 -0
  171. package/dist/src/repl/banner.js +28 -0
  172. package/dist/src/repl/boot-animation.d.ts +13 -0
  173. package/dist/src/repl/boot-animation.js +143 -0
  174. package/dist/src/repl/completer.d.ts +21 -0
  175. package/dist/src/repl/completer.js +168 -0
  176. package/dist/src/repl/context.d.ts +24 -0
  177. package/dist/src/repl/context.js +42 -0
  178. package/dist/src/repl/display-utils.d.ts +13 -0
  179. package/dist/src/repl/display-utils.js +65 -0
  180. package/dist/src/repl/event-listener.d.ts +18 -0
  181. package/dist/src/repl/event-listener.js +112 -0
  182. package/dist/src/repl/export-formatter.d.ts +8 -0
  183. package/dist/src/repl/export-formatter.js +73 -0
  184. package/dist/src/repl/ghost-text.d.ts +31 -0
  185. package/dist/src/repl/ghost-text.js +119 -0
  186. package/dist/src/repl/handoff-animation.d.ts +15 -0
  187. package/dist/src/repl/handoff-animation.js +65 -0
  188. package/dist/src/repl/history.d.ts +16 -0
  189. package/dist/src/repl/history.js +130 -0
  190. package/dist/src/repl/job-registry.d.ts +26 -0
  191. package/dist/src/repl/job-registry.js +80 -0
  192. package/dist/src/repl/magi-repl.d.ts +72 -0
  193. package/dist/src/repl/magi-repl.js +1008 -0
  194. package/dist/src/repl/multiline-input.d.ts +45 -0
  195. package/dist/src/repl/multiline-input.js +78 -0
  196. package/dist/src/repl/prompt-builder.d.ts +19 -0
  197. package/dist/src/repl/prompt-builder.js +36 -0
  198. package/dist/src/repl/repl-state.d.ts +5 -0
  199. package/dist/src/repl/repl-state.js +19 -0
  200. package/dist/src/repl/result-display.d.ts +8 -0
  201. package/dist/src/repl/result-display.js +195 -0
  202. package/dist/src/repl/session-stats.d.ts +26 -0
  203. package/dist/src/repl/session-stats.js +119 -0
  204. package/dist/src/repl/slash-commands.d.ts +60 -0
  205. package/dist/src/repl/slash-commands.js +725 -0
  206. package/dist/src/repl/terminal-sanitize.d.ts +14 -0
  207. package/dist/src/repl/terminal-sanitize.js +19 -0
  208. package/dist/src/reporters/console.d.ts +7 -0
  209. package/dist/src/reporters/console.js +78 -0
  210. package/dist/src/reporters/json.d.ts +2 -0
  211. package/dist/src/reporters/json.js +3 -0
  212. package/dist/src/reporters/markdown.d.ts +2 -0
  213. package/dist/src/reporters/markdown.js +65 -0
  214. package/dist/src/reporters/streaming.d.ts +20 -0
  215. package/dist/src/reporters/streaming.js +178 -0
  216. package/dist/src/tui/activity-log.d.ts +23 -0
  217. package/dist/src/tui/activity-log.js +67 -0
  218. package/dist/src/tui/animations.d.ts +39 -0
  219. package/dist/src/tui/animations.js +167 -0
  220. package/dist/src/tui/ansi.d.ts +28 -0
  221. package/dist/src/tui/ansi.js +51 -0
  222. package/dist/src/tui/boot-sequence.d.ts +11 -0
  223. package/dist/src/tui/boot-sequence.js +98 -0
  224. package/dist/src/tui/colors.d.ts +101 -0
  225. package/dist/src/tui/colors.js +71 -0
  226. package/dist/src/tui/header.d.ts +24 -0
  227. package/dist/src/tui/header.js +122 -0
  228. package/dist/src/tui/index.d.ts +3 -0
  229. package/dist/src/tui/index.js +3 -0
  230. package/dist/src/tui/keypress.d.ts +25 -0
  231. package/dist/src/tui/keypress.js +95 -0
  232. package/dist/src/tui/layout.d.ts +74 -0
  233. package/dist/src/tui/layout.js +171 -0
  234. package/dist/src/tui/magi-tui.d.ts +101 -0
  235. package/dist/src/tui/magi-tui.js +754 -0
  236. package/dist/src/tui/panel.d.ts +45 -0
  237. package/dist/src/tui/panel.js +292 -0
  238. package/dist/src/tui/screen-buffer.d.ts +54 -0
  239. package/dist/src/tui/screen-buffer.js +262 -0
  240. package/dist/src/tui/status-bar.d.ts +25 -0
  241. package/dist/src/tui/status-bar.js +124 -0
  242. package/dist/src/tui/terminal-detect.d.ts +26 -0
  243. package/dist/src/tui/terminal-detect.js +44 -0
  244. package/dist/src/tui/tui-helpers.d.ts +12 -0
  245. package/dist/src/tui/tui-helpers.js +37 -0
  246. package/dist/src/types/adapter.d.ts +75 -0
  247. package/dist/src/types/adapter.js +36 -0
  248. package/dist/src/types/config.d.ts +108 -0
  249. package/dist/src/types/config.js +85 -0
  250. package/dist/src/types/consensus.d.ts +55 -0
  251. package/dist/src/types/consensus.js +17 -0
  252. package/dist/src/types/core.d.ts +178 -0
  253. package/dist/src/types/core.js +85 -0
  254. package/dist/src/types/magi-api.d.ts +62 -0
  255. package/dist/src/types/magi-api.js +7 -0
  256. package/dist/src/types/phase-h.d.ts +142 -0
  257. package/dist/src/types/phase-h.js +7 -0
  258. package/dist/src/types/phase-i.d.ts +186 -0
  259. package/dist/src/types/phase-i.js +6 -0
  260. package/dist/src/types/phase-k.d.ts +259 -0
  261. package/dist/src/types/phase-k.js +6 -0
  262. package/dist/src/types/phase-l.d.ts +199 -0
  263. package/dist/src/types/phase-l.js +6 -0
  264. package/dist/src/types/pipeline.d.ts +37 -0
  265. package/dist/src/types/pipeline.js +2 -0
  266. package/dist/src/utils/abstain-factory.d.ts +2 -0
  267. package/dist/src/utils/abstain-factory.js +18 -0
  268. package/dist/src/utils/errors.d.ts +34 -0
  269. package/dist/src/utils/errors.js +59 -0
  270. package/dist/src/utils/file-validator.d.ts +50 -0
  271. package/dist/src/utils/file-validator.js +124 -0
  272. package/dist/src/utils/fire-and-forget.d.ts +5 -0
  273. package/dist/src/utils/fire-and-forget.js +10 -0
  274. package/dist/src/utils/flag-validator.d.ts +21 -0
  275. package/dist/src/utils/flag-validator.js +79 -0
  276. package/dist/src/utils/freeze.d.ts +8 -0
  277. package/dist/src/utils/freeze.js +16 -0
  278. package/dist/src/utils/language-detector.d.ts +16 -0
  279. package/dist/src/utils/language-detector.js +159 -0
  280. package/dist/src/utils/latency-tracker.d.ts +45 -0
  281. package/dist/src/utils/latency-tracker.js +100 -0
  282. package/dist/src/utils/logger.d.ts +33 -0
  283. package/dist/src/utils/logger.js +112 -0
  284. package/dist/src/utils/process.d.ts +40 -0
  285. package/dist/src/utils/process.js +253 -0
  286. package/dist/src/utils/retry.d.ts +12 -0
  287. package/dist/src/utils/retry.js +30 -0
  288. package/dist/src/utils/safe-fs.d.ts +38 -0
  289. package/dist/src/utils/safe-fs.js +56 -0
  290. package/dist/src/utils/safe-json-parse.d.ts +15 -0
  291. package/dist/src/utils/safe-json-parse.js +49 -0
  292. package/dist/src/utils/sanitize.d.ts +14 -0
  293. package/dist/src/utils/sanitize.js +186 -0
  294. package/dist/src/utils/semaphore.d.ts +22 -0
  295. package/dist/src/utils/semaphore.js +57 -0
  296. package/dist/src/utils/shutdown.d.ts +6 -0
  297. package/dist/src/utils/shutdown.js +51 -0
  298. package/dist/src/utils/tty.d.ts +5 -0
  299. package/dist/src/utils/tty.js +7 -0
  300. package/package.json +82 -0
@@ -0,0 +1,12 @@
1
+ import type { MagiDeliberation } from './types.js';
2
+ import type { MagiTask } from '../../types/core.js';
3
+ import type { KernelDependencies } from './types.js';
4
+ export declare class DeliberationKernel {
5
+ private readonly deps;
6
+ private readonly phaseRunner;
7
+ private readonly postProcessor;
8
+ private readonly middleware;
9
+ constructor(deps: KernelDependencies);
10
+ deliberate(task: MagiTask, signal?: AbortSignal): Promise<MagiDeliberation>;
11
+ private buildResult;
12
+ }
@@ -0,0 +1,303 @@
1
+ /**
2
+ * DeliberationKernel — The main deliberation loop.
3
+ *
4
+ * Responsibilities:
5
+ * - Middleware chain execution (cache check, firewall scan)
6
+ * - Pipeline config setup with sync rate weights
7
+ * - Phase loop with hard timeout
8
+ * - Early consensus exit
9
+ * - Final consensus calculation
10
+ * - Instrumentality fusion for deadlock resolution
11
+ * - Human-in-the-loop deadlock resolution
12
+ * - Build result
13
+ */
14
+ import { randomUUID } from 'node:crypto';
15
+ import { isUnanimous as isUnanimousDecision, isMajority as isMajorityDecision } from '../../types/consensus.js';
16
+ import { ConsensusEngine } from '../consensus.js';
17
+ import { HumanResolver } from '../human-resolver.js';
18
+ import { logger } from '../../utils/logger.js';
19
+ import { DeliberationTimeoutError } from '../../utils/errors.js';
20
+ import { MiddlewareChain } from '../middleware/chain.js';
21
+ import { createCacheMiddleware } from '../middleware/cache.js';
22
+ import { createFirewallMiddleware } from '../middleware/firewall.js';
23
+ import { PhaseRunner } from './phase-runner.js';
24
+ import { PostProcessor } from './post-processor.js';
25
+ export class DeliberationKernel {
26
+ deps;
27
+ phaseRunner;
28
+ postProcessor;
29
+ middleware;
30
+ constructor(deps) {
31
+ this.deps = deps;
32
+ this.phaseRunner = new PhaseRunner(deps);
33
+ this.postProcessor = new PostProcessor(deps);
34
+ // Build middleware chain (firewall FIRST, then cache)
35
+ this.middleware = new MiddlewareChain();
36
+ if (deps.modules.type666Firewall) {
37
+ this.middleware.use(createFirewallMiddleware(deps.modules.type666Firewall));
38
+ }
39
+ if (deps.modules.cache) {
40
+ this.middleware.use(createCacheMiddleware(deps.modules.cache));
41
+ }
42
+ }
43
+ async deliberate(task, signal) {
44
+ const id = task.id ?? randomUUID();
45
+ const { adapters, pipelines, contextManager, eventBus } = this.deps;
46
+ const { objectiveJudge, syncRateTracker, instrumentality } = this.deps.modules;
47
+ // Run pre-deliberation middleware chain (cache check, firewall scan, etc.)
48
+ if (this.middleware.length > 0) {
49
+ const mwCtx = {
50
+ deliberationId: id,
51
+ task,
52
+ config: {}, // not used by current middlewares
53
+ eventBus,
54
+ metadata: new Map(),
55
+ };
56
+ await this.middleware.execute(mwCtx);
57
+ if (mwCtx.blocked) {
58
+ throw new Error(mwCtx.blockedReason ?? 'Deliberation blocked by firewall');
59
+ }
60
+ if (mwCtx.skipDeliberation && mwCtx.cachedResult) {
61
+ return mwCtx.cachedResult;
62
+ }
63
+ }
64
+ const pipeline = pipelines.get(task.type);
65
+ const config = {
66
+ ...pipeline.defaultConfig,
67
+ ...task.config,
68
+ consensus: { ...pipeline.defaultConfig.consensus, ...task.config?.consensus },
69
+ };
70
+ // Phase H: Merge sync rate weights into consensus config
71
+ if (syncRateTracker) {
72
+ const units = adapters.getAll().map(a => a.unit);
73
+ const syncWeights = syncRateTracker.computeWeights(units, task.type);
74
+ if (Object.keys(syncWeights).length > 0) {
75
+ config.consensus = {
76
+ ...config.consensus,
77
+ unitWeights: { ...config.consensus.unitWeights, ...syncWeights },
78
+ };
79
+ }
80
+ }
81
+ const consensusEngine = new ConsensusEngine(config.consensus);
82
+ const startedAt = new Date();
83
+ const rounds = [];
84
+ const pendingIO = [];
85
+ await contextManager.initWorkspace(id, task);
86
+ logger.info(`MAGI deliberation started: ${id}`, { type: task.type, title: task.title });
87
+ logger.audit('deliberation.start', id, { type: task.type, title: task.title });
88
+ eventBus?.emit('deliberation:start', {
89
+ deliberationId: id,
90
+ taskType: task.type,
91
+ taskTitle: task.title,
92
+ emittedAt: new Date(),
93
+ });
94
+ // Run ObjectiveJudge for code-review/security-audit tasks (before phases)
95
+ let objectiveResult;
96
+ if (objectiveJudge && (task.type === 'code-review' || task.type === 'security-audit')) {
97
+ try {
98
+ objectiveResult = await objectiveJudge.evaluate();
99
+ logger.info('ObjectiveJudge evaluation complete', { score: objectiveResult.score });
100
+ logger.audit('objective.complete', id, { score: objectiveResult.score });
101
+ }
102
+ catch (err) {
103
+ logger.warn('ObjectiveJudge evaluation failed, continuing without', { error: String(err) });
104
+ }
105
+ }
106
+ const objectiveSummary = objectiveResult?.summary;
107
+ const objectiveScore = objectiveResult?.score;
108
+ // Hard timeout for entire deliberation
109
+ const deliberationTimeout = config.deliberationTimeoutMs;
110
+ const deadline = startedAt.getTime() + deliberationTimeout;
111
+ // Save baseline excludeFromUnanimous to prevent DummyPlug accumulation across phases
112
+ const baseExcludeFromUnanimous = [...(config.consensus.excludeFromUnanimous ?? [])];
113
+ for (const phase of config.phases) {
114
+ // P0-2: Check external abort signal before starting a new phase
115
+ if (signal?.aborted) {
116
+ throw new Error('Deliberation cancelled');
117
+ }
118
+ // Deep-clone config per phase to isolate from async mutations (fire-and-forget, event handlers).
119
+ // Prerequisite: config must be JSON-serializable (no functions, class instances, or Symbols).
120
+ let phaseConfig;
121
+ try {
122
+ phaseConfig = structuredClone(config);
123
+ }
124
+ catch {
125
+ // Fallback to JSON round-trip to deep-clone (preserves nested objects)
126
+ try {
127
+ phaseConfig = JSON.parse(JSON.stringify(config));
128
+ }
129
+ catch {
130
+ phaseConfig = { ...config };
131
+ }
132
+ }
133
+ phaseConfig.consensus.excludeFromUnanimous = [...baseExcludeFromUnanimous];
134
+ // File access requires more time for CLIs to explore the codebase
135
+ if (this.deps.fileAccessEnabled) {
136
+ phaseConfig.phaseTimeoutMs = Math.min(phaseConfig.phaseTimeoutMs * 2, 3_600_000);
137
+ }
138
+ const roundNumber = rounds.length + 1;
139
+ if (roundNumber > phaseConfig.maxRounds)
140
+ break;
141
+ // Check hard timeout before starting a new phase
142
+ if (Date.now() >= deadline) {
143
+ logger.warn(`Deliberation hard timeout reached`, { id, timeoutMs: deliberationTimeout });
144
+ logger.audit('phase.timeout', id, { phase: 'deliberation', timeoutMs: deliberationTimeout });
145
+ throw new DeliberationTimeoutError(id, deliberationTimeout);
146
+ }
147
+ logger.info(`Phase: ${phase} (round ${roundNumber})`);
148
+ logger.audit('phase.start', id, { phase, roundNumber });
149
+ const roundStart = new Date();
150
+ eventBus?.emit('phase:start', {
151
+ deliberationId: id,
152
+ phase,
153
+ roundNumber,
154
+ emittedAt: new Date(),
155
+ });
156
+ // Phase timeout with Promise.race
157
+ let opinions = await this.phaseRunner.runWithTimeout({
158
+ deliberationId: id, task, pipeline, phase,
159
+ previousRounds: rounds, config: phaseConfig, objectiveSummary,
160
+ fileAccessEnabled: this.deps.fileAccessEnabled,
161
+ }, signal);
162
+ // Post-phase processing (LCL, ATField, DummyPlug recording)
163
+ opinions = this.postProcessor.processPhaseOpinions(opinions, phase, id, task.type);
164
+ const round = {
165
+ roundNumber,
166
+ phase,
167
+ opinions,
168
+ startedAt: roundStart,
169
+ completedAt: new Date(),
170
+ };
171
+ rounds.push(round);
172
+ // Fire-and-forget: push IO to pending queue instead of awaiting
173
+ pendingIO.push(contextManager.saveRound(id, round).catch((err) => {
174
+ logger.warn('Failed to save round', { roundNumber, error: String(err) });
175
+ }));
176
+ const phaseDurationMs = round.completedAt.getTime() - round.startedAt.getTime();
177
+ logger.audit('phase.complete', id, {
178
+ phase,
179
+ roundNumber,
180
+ durationMs: phaseDurationMs,
181
+ votes: opinions.map((o) => ({ unit: o.unit, vote: o.vote })),
182
+ });
183
+ eventBus?.emit('phase:complete', {
184
+ deliberationId: id,
185
+ phase,
186
+ roundNumber,
187
+ durationMs: phaseDurationMs,
188
+ emittedAt: new Date(),
189
+ });
190
+ // Adaptive early consensus exit (skip only for final-vote)
191
+ if (phaseConfig.earlyConsensusExit && phase !== 'final-vote') {
192
+ const earlyOpinions = objectiveScore !== undefined
193
+ ? opinions.map(o => ({ ...o, confidence: o.confidence * (0.5 + 0.5 * objectiveScore) }))
194
+ : opinions;
195
+ const result = consensusEngine.calculate(earlyOpinions);
196
+ const thresholds = phaseConfig.earlyExitThresholds ?? { unanimous: 0.7, majority: 0.85 };
197
+ const isUnanimousExit = isUnanimousDecision(result.decision) && result.confidence >= thresholds.unanimous;
198
+ const isMajorityExit = isMajorityDecision(result.decision) && result.confidence >= thresholds.majority;
199
+ if (isUnanimousExit || isMajorityExit) {
200
+ const reason = isUnanimousExit ? 'unanimous_early_exit' : 'majority_early_exit';
201
+ const currentIdx = config.phases.indexOf(phase);
202
+ for (const skipped of config.phases.slice(currentIdx + 1)) {
203
+ eventBus?.emit('phase:skipped', {
204
+ deliberationId: id,
205
+ phase: skipped,
206
+ reason,
207
+ emittedAt: new Date(),
208
+ });
209
+ }
210
+ logger.info(`Early consensus reached: ${result.decision}`);
211
+ logger.audit('deliberation.complete', id, {
212
+ decision: result.decision,
213
+ method: 'early_consensus',
214
+ rounds: rounds.length,
215
+ });
216
+ await Promise.allSettled(pendingIO);
217
+ const earlyResult = this.buildResult(id, task, rounds, result, startedAt, objectiveResult);
218
+ await contextManager.saveDeliberation(earlyResult).catch((err) => {
219
+ logger.warn('Failed to save early deliberation', { error: String(err) });
220
+ });
221
+ eventBus?.emit('deliberation:complete', {
222
+ deliberationId: id,
223
+ decision: result.decision,
224
+ totalDurationMs: earlyResult.totalDurationMs,
225
+ rounds: rounds.length,
226
+ fromCache: false,
227
+ emittedAt: new Date(),
228
+ });
229
+ return earlyResult;
230
+ }
231
+ }
232
+ }
233
+ // Calculate final consensus from the last round (with objective confidence adjustment)
234
+ const lastRound = rounds[rounds.length - 1];
235
+ const finalOpinions = lastRound?.opinions ?? [];
236
+ const adjustedFinalOpinions = objectiveScore !== undefined
237
+ ? finalOpinions.map(o => ({ ...o, confidence: o.confidence * (0.5 + 0.5 * objectiveScore) }))
238
+ : finalOpinions;
239
+ let consensus = consensusEngine.calculate(adjustedFinalOpinions);
240
+ // Phase I: Instrumentality fusion for deadlock resolution
241
+ if (consensus.decision === 'DEADLOCK' && instrumentality &&
242
+ instrumentality.shouldTrigger(rounds, consensus.decision)) {
243
+ try {
244
+ const fusionResult = await instrumentality.fuse(adjustedFinalOpinions, task);
245
+ // Replace consensus with fused opinion result
246
+ const fusedOpinions = [fusionResult.fused];
247
+ consensus = consensusEngine.calculate(fusedOpinions);
248
+ logger.info('Instrumentality fusion resolved deadlock', { decision: consensus.decision });
249
+ logger.audit('instrumentality.resolve', id, { decision: consensus.decision });
250
+ }
251
+ catch (err) {
252
+ logger.warn('Instrumentality fusion failed, falling through', { error: String(err) });
253
+ }
254
+ }
255
+ // Human-in-the-loop deadlock resolution
256
+ if (consensus.decision === 'DEADLOCK' && config.consensus.deadlockStrategy === 'human-in-the-loop') {
257
+ const humanResolver = new HumanResolver();
258
+ if (humanResolver.isAvailable()) {
259
+ consensus = await humanResolver.resolve(adjustedFinalOpinions, consensus.votes);
260
+ logger.info('Deadlock resolved by human', { decision: consensus.decision });
261
+ logger.audit('human.resolve', id, { decision: consensus.decision });
262
+ }
263
+ }
264
+ // Flush all pending round IO before saving final deliberation
265
+ await Promise.allSettled(pendingIO);
266
+ const deliberation = this.buildResult(id, task, rounds, consensus, startedAt, objectiveResult);
267
+ await contextManager.saveDeliberation(deliberation);
268
+ // Post-deliberation side effects
269
+ await this.postProcessor.runPostDeliberation(id, task, lastRound, consensus, deliberation);
270
+ logger.info(`MAGI deliberation complete: ${consensus.decision}`, {
271
+ id,
272
+ rounds: rounds.length,
273
+ totalDurationMs: deliberation.totalDurationMs,
274
+ });
275
+ logger.audit('deliberation.complete', id, {
276
+ decision: consensus.decision,
277
+ rounds: rounds.length,
278
+ totalDurationMs: deliberation.totalDurationMs,
279
+ });
280
+ eventBus?.emit('deliberation:complete', {
281
+ deliberationId: id,
282
+ decision: consensus.decision,
283
+ totalDurationMs: deliberation.totalDurationMs,
284
+ rounds: rounds.length,
285
+ fromCache: false,
286
+ emittedAt: new Date(),
287
+ });
288
+ return deliberation;
289
+ }
290
+ buildResult(id, task, rounds, consensus, startedAt, objectiveResult) {
291
+ const completedAt = new Date();
292
+ return {
293
+ id,
294
+ task,
295
+ rounds,
296
+ consensus,
297
+ totalDurationMs: completedAt.getTime() - startedAt.getTime(),
298
+ startedAt,
299
+ completedAt,
300
+ objectiveResult,
301
+ };
302
+ }
303
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Kernel module re-exports.
3
+ */
4
+ export { DeliberationKernel } from './deliberation-kernel.js';
5
+ export { PhaseRunner } from './phase-runner.js';
6
+ export { UnitExecutor } from './unit-executor.js';
7
+ export { PostProcessor } from './post-processor.js';
8
+ export type { KernelDependencies, OptionalModules, UnitExecutionParams, PhaseRunParams, DeliberationContext, } from './types.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Kernel module re-exports.
3
+ */
4
+ export { DeliberationKernel } from './deliberation-kernel.js';
5
+ export { PhaseRunner } from './phase-runner.js';
6
+ export { UnitExecutor } from './unit-executor.js';
7
+ export { PostProcessor } from './post-processor.js';
@@ -0,0 +1,10 @@
1
+ import type { KernelDependencies, PhaseRunParams, MagiOpinion } from './types.js';
2
+ export declare class PhaseRunner {
3
+ private readonly deps;
4
+ private readonly unitExecutor;
5
+ constructor(deps: KernelDependencies);
6
+ /** Execute a phase with a timeout guard (Promise.race). */
7
+ runWithTimeout(params: PhaseRunParams, externalSignal?: AbortSignal): Promise<MagiOpinion[]>;
8
+ /** Execute a phase: filter units, run in parallel, apply DummyPlug/Iruel/Offline. */
9
+ private run;
10
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * PhaseRunner — Executes a deliberation phase across all active MAGI units.
3
+ *
4
+ * Responsibilities:
5
+ * - AbortController + phase timeout management
6
+ * - UmbilicalCable unit filtering (circuit breaker, battery depletion)
7
+ * - Parallel execution via Promise.allSettled
8
+ * - UmbilicalCable result recording (success/failure)
9
+ * - DummyPlug replacement for ABSTAIN units
10
+ * - Iruel consistency verification
11
+ * - Offline fallback for skipped adapters
12
+ */
13
+ import { logger } from '../../utils/logger.js';
14
+ import { createAbstainOpinion } from '../../utils/abstain-factory.js';
15
+ import { PhaseTimeoutError } from '../../utils/errors.js';
16
+ import { UnitExecutor } from './unit-executor.js';
17
+ export class PhaseRunner {
18
+ deps;
19
+ unitExecutor;
20
+ constructor(deps) {
21
+ this.deps = deps;
22
+ this.unitExecutor = new UnitExecutor(deps);
23
+ }
24
+ /** Execute a phase with a timeout guard (Promise.race). */
25
+ async runWithTimeout(params, externalSignal) {
26
+ const { config } = params;
27
+ const controller = new AbortController();
28
+ // Link external signal (from REPL Ctrl+C) to internal phase controller
29
+ const onExternalAbort = () => controller.abort();
30
+ externalSignal?.addEventListener('abort', onExternalAbort, { once: true });
31
+ const phasePromise = this.run(params, controller.signal);
32
+ let timer;
33
+ const timeoutPromise = new Promise((_, reject) => {
34
+ timer = setTimeout(() => {
35
+ controller.abort(); // Signal child processes to terminate
36
+ logger.audit('phase.timeout', params.deliberationId, {
37
+ phase: params.phase, timeoutMs: config.phaseTimeoutMs,
38
+ });
39
+ reject(new PhaseTimeoutError(params.phase, config.phaseTimeoutMs));
40
+ }, config.phaseTimeoutMs);
41
+ });
42
+ try {
43
+ return await Promise.race([phasePromise, timeoutPromise]);
44
+ }
45
+ finally {
46
+ clearTimeout(timer);
47
+ externalSignal?.removeEventListener('abort', onExternalAbort);
48
+ }
49
+ }
50
+ /** Execute a phase: filter units, run in parallel, apply DummyPlug/Iruel/Offline. */
51
+ async run(params, signal) {
52
+ const { deliberationId, task, pipeline, phase, previousRounds, config, objectiveSummary, fileAccessEnabled } = params;
53
+ const { adapters, eventBus } = this.deps;
54
+ const { umbilicalCable, dummyPlug, iruelBattle, offlineMode } = this.deps.modules;
55
+ const allAdapters = adapters.getAll();
56
+ // Phase H: Filter out disconnected + battery-depleted units (with circuit breaker)
57
+ const activeAdapters = allAdapters.filter(adapter => {
58
+ if (umbilicalCable) {
59
+ // Circuit breaker: fail fast for OPEN circuits
60
+ if (!umbilicalCable.shouldAllow(adapter.unit)) {
61
+ logger.info(`${adapter.unit} skipped: circuit breaker OPEN`);
62
+ return false;
63
+ }
64
+ const status = umbilicalCable.getStatus(adapter.unit);
65
+ if (status === 'disconnected' && umbilicalCable.isBatteryDepleted(adapter.unit)) {
66
+ logger.info(`${adapter.unit} skipped: disconnected + battery depleted`);
67
+ return false;
68
+ }
69
+ }
70
+ return true;
71
+ });
72
+ // All phases run in parallel (Promise.allSettled for graceful degradation)
73
+ const results = await Promise.allSettled(activeAdapters.map((adapter) => this.unitExecutor.execute({
74
+ deliberationId, adapter, task, pipeline, phase,
75
+ previousRounds, config, objectiveSummary, signal,
76
+ fileAccessEnabled,
77
+ })));
78
+ const opinions = results.map((result, i) => {
79
+ const adapter = activeAdapters[i];
80
+ if (result.status === 'fulfilled') {
81
+ // Phase H: Record success in UmbilicalCable
82
+ umbilicalCable?.recordResult(adapter.unit, 'SUCCESS', eventBus);
83
+ return result.value;
84
+ }
85
+ // Phase H: Record failure in UmbilicalCable
86
+ const errorCode = String(result.reason).includes('TIMEOUT') ? 'TIMEOUT' : 'CRASH';
87
+ umbilicalCable?.recordResult(adapter.unit, errorCode, eventBus);
88
+ // On failure, produce an ABSTAIN opinion
89
+ logger.warn(`${adapter.displayName} failed in phase ${phase}`, {
90
+ error: String(result.reason),
91
+ });
92
+ logger.audit('adapter.failure', deliberationId, {
93
+ unit: adapter.unit,
94
+ phase,
95
+ error: String(result.reason),
96
+ });
97
+ eventBus?.emit('unit:error', {
98
+ deliberationId,
99
+ unit: adapter.unit,
100
+ phase,
101
+ error: String(result.reason),
102
+ emittedAt: new Date(),
103
+ });
104
+ return createAbstainOpinion(adapter.unit, `${adapter.displayName} failed: ${result.reason?.message ?? 'unknown error'}`, ['Adapter execution failed']);
105
+ });
106
+ // Phase H: Replace ABSTAIN/down units with DummyPlug proxy opinions
107
+ if (dummyPlug) {
108
+ for (let i = 0; i < opinions.length; i++) {
109
+ const op = opinions[i];
110
+ if (op.vote === 'ABSTAIN' && op.confidence === 0) {
111
+ const proxy = dummyPlug.generateProxy(op.unit, activeAdapters.map(a => a.unit), opinions, task.type);
112
+ if (proxy) {
113
+ opinions[i] = proxy;
114
+ logger.info(`DummyPlug activated for ${op.unit}`);
115
+ logger.audit('dummyplug.activate', deliberationId, { unit: op.unit });
116
+ eventBus?.emit('dummyplug:activated', {
117
+ deliberationId, unit: op.unit,
118
+ confidence: proxy.confidence, profileSamples: proxy.profileSamples,
119
+ emittedAt: new Date(),
120
+ });
121
+ }
122
+ }
123
+ }
124
+ // Set excludeFromUnanimous for dummy plug units
125
+ const dummyUnits = dummyPlug.getDummyUnits(opinions);
126
+ if (dummyUnits.length > 0) {
127
+ config.consensus = {
128
+ ...config.consensus,
129
+ excludeFromUnanimous: [
130
+ ...(config.consensus.excludeFromUnanimous ?? []),
131
+ ...dummyUnits,
132
+ ],
133
+ };
134
+ }
135
+ }
136
+ // Phase L: Iruel Battle consistency verification + filtering
137
+ if (iruelBattle) {
138
+ for (let i = 0; i < opinions.length; i++) {
139
+ const op = opinions[i];
140
+ const check = iruelBattle.verifyConsistency(op, opinions);
141
+ iruelBattle.detectCorruption(op, check);
142
+ opinions[i] = iruelBattle.filterOpinion(op);
143
+ }
144
+ }
145
+ // Phase H: Add offline fallback opinions for skipped (depleted) adapters
146
+ if (offlineMode) {
147
+ const skipped = allAdapters.filter(a => !activeAdapters.includes(a));
148
+ for (const adapter of skipped) {
149
+ const fallback = offlineMode.generateFallbackOpinion(adapter.unit, task);
150
+ opinions.push(fallback);
151
+ }
152
+ }
153
+ return opinions;
154
+ }
155
+ }
@@ -0,0 +1,17 @@
1
+ import type { KernelDependencies, MagiOpinion, MagiTask, DeliberationRound, MagiDeliberation } from './types.js';
2
+ import type { ConsensusResult } from '../../types/consensus.js';
3
+ export declare class PostProcessor {
4
+ private readonly deps;
5
+ constructor(deps: KernelDependencies);
6
+ /**
7
+ * Process opinions after a phase completes.
8
+ * - LCL purify (cross-examination only)
9
+ * - ATField bias analysis
10
+ * - DummyPlug profile recording
11
+ */
12
+ processPhaseOpinions(opinions: MagiOpinion[], phase: string, deliberationId: string, taskType: string): MagiOpinion[];
13
+ /**
14
+ * Run all post-deliberation side effects (mostly fire-and-forget).
15
+ */
16
+ runPostDeliberation(deliberationId: string, task: MagiTask, lastRound: DeliberationRound | undefined, consensus: ConsensusResult, deliberation: MagiDeliberation): Promise<void>;
17
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * PostProcessor — Handles post-phase and post-deliberation side effects.
3
+ *
4
+ * Phase opinion processing (after each phase):
5
+ * - LCL purify opinions
6
+ * - ATField bias analysis
7
+ * - DummyPlug profile recording
8
+ *
9
+ * Post-deliberation processing (after consensus is determined):
10
+ * - SyncRate update
11
+ * - Gospel chronicle record
12
+ * - Engram memory record
13
+ * - Drift detection
14
+ * - Firewall learning
15
+ * - Nebuchadnezzar key reset
16
+ * - Cache save
17
+ * - Token persist
18
+ */
19
+ import { logger } from '../../utils/logger.js';
20
+ import { fireAndForget } from '../../utils/fire-and-forget.js';
21
+ export class PostProcessor {
22
+ deps;
23
+ constructor(deps) {
24
+ this.deps = deps;
25
+ }
26
+ /**
27
+ * Process opinions after a phase completes.
28
+ * - LCL purify (cross-examination only)
29
+ * - ATField bias analysis
30
+ * - DummyPlug profile recording
31
+ */
32
+ processPhaseOpinions(opinions, phase, deliberationId, taskType) {
33
+ let processed = opinions;
34
+ const { lclManager, atField, dummyPlug } = this.deps.modules;
35
+ // Phase I: LCL purify opinions before cross-examination
36
+ if (lclManager && phase === 'cross-examination') {
37
+ for (let i = 0; i < processed.length; i++) {
38
+ const result = lclManager.purify(processed[i], deliberationId);
39
+ if (result.purified) {
40
+ processed[i] = { ...processed[i], confidence: result.adjustedConfidence };
41
+ }
42
+ }
43
+ }
44
+ // Phase H: A.T. Field bias analysis
45
+ if (atField) {
46
+ const biasResult = atField.analyze(processed, this.deps.eventBus, deliberationId);
47
+ if (biasResult.biasWarning && biasResult.confidenceDiscount > 0) {
48
+ processed = processed.map(o => ({
49
+ ...o,
50
+ confidence: o.confidence * (1 - biasResult.confidenceDiscount),
51
+ }));
52
+ }
53
+ }
54
+ // Phase H: Record profiles for DummyPlug (exclude dummy opinions)
55
+ if (dummyPlug) {
56
+ for (const opinion of processed) {
57
+ if (!('isDummyPlug' in opinion)) {
58
+ dummyPlug.recordOpinion(opinion, taskType);
59
+ }
60
+ }
61
+ }
62
+ return processed;
63
+ }
64
+ /**
65
+ * Run all post-deliberation side effects (mostly fire-and-forget).
66
+ */
67
+ async runPostDeliberation(deliberationId, task, lastRound, consensus, deliberation) {
68
+ const { adapters, eventBus } = this.deps;
69
+ const { syncRateTracker, gospel, engramManager, driftDetector, type666Firewall, nebuchadnezzarKey, cache, tokenTracker, } = this.deps.modules;
70
+ // Phase H: Update sync rates for all units
71
+ if (syncRateTracker && lastRound) {
72
+ const units = adapters.getAll().map(a => a.unit);
73
+ for (const opinion of lastRound.opinions) {
74
+ syncRateTracker.update(opinion.unit, task.type, opinion.vote, consensus.decision);
75
+ }
76
+ const rates = syncRateTracker.getAllRates(units, task.type);
77
+ eventBus?.emit('syncrate:updated', {
78
+ deliberationId, rates, domain: task.type, emittedAt: new Date(),
79
+ });
80
+ // Berserk check
81
+ const berserk = syncRateTracker.checkBerserk(units, task.type);
82
+ if (berserk) {
83
+ eventBus?.emit('berserk:warning', {
84
+ deliberationId, totalSyncRate: berserk.totalRate, threshold: 4.0,
85
+ units: berserk.rates, emittedAt: new Date(),
86
+ });
87
+ }
88
+ fireAndForget(syncRateTracker.persist(), 'syncrate.persist');
89
+ }
90
+ // Phase H: Record in Gospel chronicle
91
+ if (gospel) {
92
+ fireAndForget(gospel.record(deliberation, eventBus), 'gospel.record');
93
+ }
94
+ // Phase I: Record in engram memory + drift detection (fire-and-forget)
95
+ if (engramManager) {
96
+ fireAndForget(engramManager.recordDeliberation(deliberation), 'engram.record');
97
+ }
98
+ if (driftDetector && lastRound) {
99
+ for (const opinion of lastRound.opinions) {
100
+ driftDetector.updateVector(opinion.unit, opinion, consensus.decision);
101
+ driftDetector.checkDrift(opinion.unit, eventBus);
102
+ }
103
+ }
104
+ // Phase K: Firewall learns from deliberation (fire-and-forget)
105
+ if (type666Firewall) {
106
+ try {
107
+ type666Firewall.learnFromDeliberation({ task, consensus });
108
+ }
109
+ catch (err) {
110
+ logger.debug('Firewall learn failed', { error: String(err) });
111
+ }
112
+ }
113
+ // Phase K: Reset Nebuchadnezzar consecutive overrides on normal completion
114
+ if (nebuchadnezzarKey) {
115
+ nebuchadnezzarKey.resetConsecutiveOverrides();
116
+ }
117
+ // Cache result (fire-and-forget)
118
+ if (cache) {
119
+ try {
120
+ cache.set(task, deliberation);
121
+ }
122
+ catch (err) {
123
+ logger.debug('Cache set failed', { error: String(err) });
124
+ }
125
+ }
126
+ // Persist token data (fire-and-forget)
127
+ if (tokenTracker) {
128
+ fireAndForget(tokenTracker.persist(deliberationId), 'token.persist');
129
+ }
130
+ }
131
+ }