@jungjaehoon/mama-os 0.40.0 → 0.42.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 (135) hide show
  1. package/README.md +2 -2
  2. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  3. package/dist/agent/code-act/host-bridge.js +0 -22
  4. package/dist/agent/code-act/host-bridge.js.map +1 -1
  5. package/dist/agent/gateway-tool-executor.d.ts +6 -7
  6. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  7. package/dist/agent/gateway-tool-executor.js +49 -76
  8. package/dist/agent/gateway-tool-executor.js.map +1 -1
  9. package/dist/agent/gateway-tools.md +1 -3
  10. package/dist/agent/tool-registry.d.ts.map +1 -1
  11. package/dist/agent/tool-registry.js +6 -18
  12. package/dist/agent/tool-registry.js.map +1 -1
  13. package/dist/agent/types.d.ts +1 -8
  14. package/dist/agent/types.d.ts.map +1 -1
  15. package/dist/agent/types.js.map +1 -1
  16. package/dist/api/graph-api.d.ts.map +1 -1
  17. package/dist/api/graph-api.js +23 -4
  18. package/dist/api/graph-api.js.map +1 -1
  19. package/dist/cli/commands/start.d.ts +45 -52
  20. package/dist/cli/commands/start.d.ts.map +1 -1
  21. package/dist/cli/commands/start.js +292 -202
  22. package/dist/cli/commands/start.js.map +1 -1
  23. package/dist/cli/config/types.d.ts.map +1 -1
  24. package/dist/cli/config/types.js +0 -2
  25. package/dist/cli/config/types.js.map +1 -1
  26. package/dist/cli/runtime/api-routes-init.d.ts +0 -3
  27. package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
  28. package/dist/cli/runtime/api-routes-init.js +8 -32
  29. package/dist/cli/runtime/api-routes-init.js.map +1 -1
  30. package/dist/cli/runtime/mama-core-init.d.ts.map +1 -1
  31. package/dist/cli/runtime/mama-core-init.js +2 -0
  32. package/dist/cli/runtime/mama-core-init.js.map +1 -1
  33. package/dist/connectors/private-connector-policy.d.ts +1 -3
  34. package/dist/connectors/private-connector-policy.d.ts.map +1 -1
  35. package/dist/connectors/private-connector-policy.js +1 -26
  36. package/dist/connectors/private-connector-policy.js.map +1 -1
  37. package/dist/gateways/context-injector.d.ts +10 -0
  38. package/dist/gateways/context-injector.d.ts.map +1 -1
  39. package/dist/gateways/context-injector.js.map +1 -1
  40. package/dist/gateways/message-router.d.ts +4 -0
  41. package/dist/gateways/message-router.d.ts.map +1 -1
  42. package/dist/gateways/message-router.js +88 -5
  43. package/dist/gateways/message-router.js.map +1 -1
  44. package/dist/multi-agent/dashboard-agent-persona.d.ts +1 -1
  45. package/dist/multi-agent/dashboard-agent-persona.d.ts.map +1 -1
  46. package/dist/multi-agent/dashboard-agent-persona.js +6 -7
  47. package/dist/multi-agent/dashboard-agent-persona.js.map +1 -1
  48. package/dist/operator/board-pipeline-render.d.ts +17 -0
  49. package/dist/operator/board-pipeline-render.d.ts.map +1 -0
  50. package/dist/operator/board-pipeline-render.js +73 -0
  51. package/dist/operator/board-pipeline-render.js.map +1 -0
  52. package/dist/operator/board-slot-instructions.d.ts +0 -8
  53. package/dist/operator/board-slot-instructions.d.ts.map +1 -1
  54. package/dist/operator/board-slot-instructions.js +3 -37
  55. package/dist/operator/board-slot-instructions.js.map +1 -1
  56. package/dist/operator/console-brief.d.ts +1 -1
  57. package/dist/operator/console-brief.d.ts.map +1 -1
  58. package/dist/operator/console-brief.js +5 -4
  59. package/dist/operator/console-brief.js.map +1 -1
  60. package/dist/operator/learning-context.d.ts +49 -0
  61. package/dist/operator/learning-context.d.ts.map +1 -0
  62. package/dist/operator/learning-context.js +129 -0
  63. package/dist/operator/learning-context.js.map +1 -0
  64. package/dist/operator/learning-markers.d.ts +19 -0
  65. package/dist/operator/learning-markers.d.ts.map +1 -0
  66. package/dist/operator/learning-markers.js +147 -0
  67. package/dist/operator/learning-markers.js.map +1 -0
  68. package/dist/operator/learning-read.d.ts +16 -0
  69. package/dist/operator/learning-read.d.ts.map +1 -0
  70. package/dist/operator/learning-read.js +18 -0
  71. package/dist/operator/learning-read.js.map +1 -0
  72. package/dist/operator/owner-event-inbox.d.ts +10 -1
  73. package/dist/operator/owner-event-inbox.d.ts.map +1 -1
  74. package/dist/operator/owner-event-inbox.js +22 -6
  75. package/dist/operator/owner-event-inbox.js.map +1 -1
  76. package/dist/operator/owner-event-loop.d.ts +4 -2
  77. package/dist/operator/owner-event-loop.d.ts.map +1 -1
  78. package/dist/operator/owner-event-loop.js +20 -3
  79. package/dist/operator/owner-event-loop.js.map +1 -1
  80. package/dist/operator/owner-event-outcome.d.ts +3 -3
  81. package/dist/operator/owner-event-outcome.d.ts.map +1 -1
  82. package/dist/operator/owner-event-outcome.js +66 -9
  83. package/dist/operator/owner-event-outcome.js.map +1 -1
  84. package/dist/operator/owner-event-policy.d.ts.map +1 -1
  85. package/dist/operator/owner-event-policy.js +18 -8
  86. package/dist/operator/owner-event-policy.js.map +1 -1
  87. package/dist/operator/owner-event-prompt.d.ts +4 -0
  88. package/dist/operator/owner-event-prompt.d.ts.map +1 -1
  89. package/dist/operator/owner-event-prompt.js +15 -5
  90. package/dist/operator/owner-event-prompt.js.map +1 -1
  91. package/dist/operator/report-context.d.ts +12 -0
  92. package/dist/operator/report-context.d.ts.map +1 -1
  93. package/dist/operator/report-context.js +60 -0
  94. package/dist/operator/report-context.js.map +1 -1
  95. package/dist/operator/task-ledger.d.ts +20 -1
  96. package/dist/operator/task-ledger.d.ts.map +1 -1
  97. package/dist/operator/task-ledger.js +58 -1
  98. package/dist/operator/task-ledger.js.map +1 -1
  99. package/dist/operator/temporal-worker.d.ts +0 -1
  100. package/dist/operator/temporal-worker.d.ts.map +1 -1
  101. package/dist/operator/temporal-worker.js +0 -29
  102. package/dist/operator/temporal-worker.js.map +1 -1
  103. package/dist/operator/turn-observer.d.ts +34 -0
  104. package/dist/operator/turn-observer.d.ts.map +1 -0
  105. package/dist/operator/turn-observer.js +79 -0
  106. package/dist/operator/turn-observer.js.map +1 -0
  107. package/dist/operator/worker-run.d.ts +1 -1
  108. package/dist/operator/worker-run.d.ts.map +1 -1
  109. package/dist/operator/worker-run.js +5 -4
  110. package/dist/operator/worker-run.js.map +1 -1
  111. package/dist/operator/workorder-consumer.d.ts +23 -2
  112. package/dist/operator/workorder-consumer.d.ts.map +1 -1
  113. package/dist/operator/workorder-consumer.js +99 -1
  114. package/dist/operator/workorder-consumer.js.map +1 -1
  115. package/dist/operator/workorder-hooks.d.ts +1 -7
  116. package/dist/operator/workorder-hooks.d.ts.map +1 -1
  117. package/dist/operator/workorder-hooks.js +1 -5
  118. package/dist/operator/workorder-hooks.js.map +1 -1
  119. package/dist/operator/workorder-publishers.d.ts +0 -7
  120. package/dist/operator/workorder-publishers.d.ts.map +1 -1
  121. package/dist/operator/workorder-publishers.js +0 -22
  122. package/dist/operator/workorder-publishers.js.map +1 -1
  123. package/package.json +1 -1
  124. package/dist/db/migrations/owner-event-board-refresh.d.ts +0 -10
  125. package/dist/db/migrations/owner-event-board-refresh.d.ts.map +0 -1
  126. package/dist/db/migrations/owner-event-board-refresh.js +0 -27
  127. package/dist/db/migrations/owner-event-board-refresh.js.map +0 -1
  128. package/dist/operator/briefs.d.ts +0 -50
  129. package/dist/operator/briefs.d.ts.map +0 -1
  130. package/dist/operator/briefs.js +0 -451
  131. package/dist/operator/briefs.js.map +0 -1
  132. package/dist/operator/owner-event-board-refresh.d.ts +0 -51
  133. package/dist/operator/owner-event-board-refresh.d.ts.map +0 -1
  134. package/dist/operator/owner-event-board-refresh.js +0 -260
  135. package/dist/operator/owner-event-board-refresh.js.map +0 -1
@@ -45,7 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.OPERATOR_REPORT_TOOL_POLICY = exports.WORKORDER_TOOL_POLICIES = void 0;
48
+ exports.OPERATOR_REPORT_TOOL_POLICY = exports.TURN_KIND_BLOCKED_TOOLS = exports.SCHEDULED_TURN_BLOCKED_TOOLS = exports.TURN_KIND_REQUIRED_TOOLS = exports.ADMINISTRATION_TOOLS = exports.ONE_AGENT_TURN_POLICY = void 0;
49
49
  exports.workOrderActivityDetails = workOrderActivityDetails;
50
50
  exports.createCorePrincipalRegistry = createCorePrincipalRegistry;
51
51
  exports.createCorePrincipalResolver = createCorePrincipalResolver;
@@ -60,14 +60,13 @@ exports.causeEventIdsFromPayload = causeEventIdsFromPayload;
60
60
  exports.workOrderEnvelopeScope = workOrderEnvelopeScope;
61
61
  exports.temporalTaskBinding = temporalTaskBinding;
62
62
  exports.buildOperatorReportAgentPolicy = buildOperatorReportAgentPolicy;
63
- exports.buildWorkOrderAgentPolicy = buildWorkOrderAgentPolicy;
63
+ exports.isOutboundToolName = isOutboundToolName;
64
+ exports.buildTurnAgentPolicy = buildTurnAgentPolicy;
64
65
  exports.bindCodeActParentModelRun = bindCodeActParentModelRun;
65
66
  exports.finalizeCodeActParentModelRun = finalizeCodeActParentModelRun;
66
67
  exports.failCodeActParentModelRun = failCodeActParentModelRun;
67
68
  exports.buildSystemAgentProcessDefaults = buildSystemAgentProcessDefaults;
68
- exports.buildOwnerEventBoardRefreshRuntime = buildOwnerEventBoardRefreshRuntime;
69
69
  exports.resolveOwnerEventTerminalReceipt = resolveOwnerEventTerminalReceipt;
70
- exports.buildOwnerWorkOrderRequestHandler = buildOwnerWorkOrderRequestHandler;
71
70
  exports.startCommand = startCommand;
72
71
  exports.buildStartOnboardingOutput = buildStartOnboardingOutput;
73
72
  exports.runAgentLoop = runAgentLoop;
@@ -135,11 +134,12 @@ const query_tools_js_1 = require("../../connectors/trello/query-tools.js");
135
134
  const console_brief_js_1 = require("../../operator/console-brief.js");
136
135
  const task_ledger_js_1 = require("../../operator/task-ledger.js");
137
136
  const board_refresh_gate_js_1 = require("../../operator/board-refresh-gate.js");
138
- const workorder_publishers_js_1 = require("../../operator/workorder-publishers.js");
139
137
  const owner_event_inbox_js_1 = require("../../operator/owner-event-inbox.js");
140
138
  const owner_event_effects_js_1 = require("../../operator/owner-event-effects.js");
141
- const owner_event_board_refresh_js_1 = require("../../operator/owner-event-board-refresh.js");
142
139
  const owner_event_loop_js_1 = require("../../operator/owner-event-loop.js");
140
+ const board_pipeline_render_js_1 = require("../../operator/board-pipeline-render.js");
141
+ const learning_context_js_1 = require("../../operator/learning-context.js");
142
+ const learning_read_js_1 = require("../../operator/learning-read.js");
143
143
  const owner_event_prompt_js_1 = require("../../operator/owner-event-prompt.js");
144
144
  const owner_event_policy_js_1 = require("../../operator/owner-event-policy.js");
145
145
  const leg_cadence_js_1 = require("../../operator/leg-cadence.js");
@@ -156,7 +156,6 @@ const principalRegistryLogger = new DebugLogger('PrincipalRegistry');
156
156
  function workOrderActivityDetails(event) {
157
157
  return event.briefHash ? { brief_hash: event.briefHash } : undefined;
158
158
  }
159
- const ownerWorkOrderLogger = new DebugLogger('OwnerWorkOrder');
160
159
  const DISABLED_PRIVATE_CONNECTOR_POLICY = (0, private_connector_policy_js_1.resolvePrivateConnectorPolicy)({
161
160
  ok: true,
162
161
  config: {},
@@ -393,12 +392,18 @@ function causeEventIdsFromPayload(payload) {
393
392
  }
394
393
  function workOrderEnvelopeScope(input) {
395
394
  const isTemporal = input.workKind === 'temporal';
396
- const surface = (0, private_connector_policy_js_1.resolveWorkOrderPrivateSurface)(input.workKind);
395
+ // One principal for every turn; what differs per kind is WHICH connectors the run
396
+ // may read, and that is data: a recheck reads its task's connector or nothing, a
397
+ // wiki turn reads no PRIVATE connector (personal channels never feed public pages),
398
+ // the board and curation turns keep the lane's configured connectors.
399
+ const surface = exports.ONE_AGENT_TURN_POLICY.roleName;
397
400
  const candidateConnectors = isTemporal
398
401
  ? input.temporalBinding
399
402
  ? [input.temporalBinding.connector]
400
403
  : []
401
- : input.laneConnectors;
404
+ : input.workKind === 'wiki'
405
+ ? input.laneConnectors.filter((name) => !input.privateConnectorPolicy.enabledPrivateConnectors.includes(name))
406
+ : input.laneConnectors;
402
407
  return {
403
408
  project_refs: [{ kind: 'project', id: input.projectId }],
404
409
  // A temporal run reads its task's connector or nothing. Every other lane keeps the
@@ -426,6 +431,11 @@ function workOrderEnvelopeScope(input) {
426
431
  },
427
432
  ]
428
433
  : []),
434
+ // Same rule for a board reconcile: the run is bound to the channel whose delta it
435
+ // judges, and connector memories are scoped by the canonical channel key.
436
+ ...(input.workKind === 'board' && input.reconcileChannelKey
437
+ ? [{ kind: 'channel', id: input.reconcileChannelKey }]
438
+ : []),
429
439
  ],
430
440
  allowed_destinations: [],
431
441
  };
@@ -453,48 +463,115 @@ function buildCodeActRole(policy) {
453
463
  sensitiveAccess: false,
454
464
  };
455
465
  }
456
- // Stage-2 workers are short-lived operator jobs, not standing multi-agent
457
- // personas. Their permissions must therefore be complete on a default install
458
- // and must not vary with optional legacy agent configuration.
459
- exports.WORKORDER_TOOL_POLICIES = {
460
- board: {
461
- roleName: 'workorder-board',
462
- allowedTools: [
463
- 'agent_notices',
464
- 'changes_read',
465
- 'context_compile',
466
- 'contract_no_update',
467
- 'mama_search',
468
- 'report_publish',
469
- 'task_create',
470
- 'task_external_correlation',
471
- 'task_external_bind',
472
- 'task_lifecycle_reconcile',
473
- 'task_list',
474
- 'task_update',
475
- 'trello_card',
476
- 'trello_kanban',
477
- 'trello_search',
478
- ],
479
- },
480
- wiki: {
481
- roleName: 'workorder-wiki',
482
- allowedTools: ['agent_notices', 'context_compile', 'mama_search', 'obsidian', 'wiki_publish'],
483
- },
484
- 'memory-curation': {
485
- roleName: 'workorder-memory-curation',
486
- allowedTools: ['agent_notices', 'mama_save', 'mama_search'],
487
- },
488
- temporal: {
489
- roleName: 'workorder-temporal',
490
- allowedTools: [
491
- 'agent_notices',
492
- 'context_compile',
493
- 'schedule_upcoming',
494
- 'task_list',
495
- 'task_temporal_reconcile',
496
- ],
497
- },
466
+ /**
467
+ * One MAMA: every scheduled turn runs as the SAME principal the owner console and the
468
+ * event turn use. `roleName` is not a label - resolvePrivatePrincipalSurface switches on
469
+ * it and falls through to 'multi-agent-generic' for anything it does not know, which
470
+ * splits the advertised catalog from the execution envelope.
471
+ */
472
+ exports.ONE_AGENT_TURN_POLICY = { roleName: 'owner_console' };
473
+ /** Owner-authored chat only: administration never runs unattended. */
474
+ exports.ADMINISTRATION_TOOLS = new Set([
475
+ 'member_register',
476
+ 'member_suspend',
477
+ 'member_offboard',
478
+ 'member_scope_grant',
479
+ 'member_scope_revoke',
480
+ 'console_brief_update',
481
+ 'report_request',
482
+ ]);
483
+ /**
484
+ * Per-turn-kind artifact tools, projected by the HOST. These exist only for scheduled
485
+ * turns and are deliberately absent from the chat grant: a chat turn never publishes a
486
+ * board slot or a wiki page and never files a temporal receipt. They are the tools the
487
+ * turn-kind section instructs the turn to use, so grant and instruction cannot drift.
488
+ */
489
+ exports.TURN_KIND_REQUIRED_TOOLS = {
490
+ board: [
491
+ 'agent_notices',
492
+ 'contract_no_update',
493
+ 'report_publish',
494
+ 'task_external_correlation',
495
+ 'task_external_bind',
496
+ 'task_lifecycle_reconcile',
497
+ ],
498
+ wiki: ['agent_notices', 'contract_no_update', 'wiki_publish'],
499
+ 'memory-curation': ['agent_notices', 'contract_no_update'],
500
+ temporal: ['agent_notices', 'contract_no_update', 'task_temporal_reconcile'],
501
+ };
502
+ /**
503
+ * Blocked on EVERY unattended turn. Deliverable, image and Drive tools belong to the
504
+ * owner conversation, and the tier-2 Code-Act projection refuses them anyway - a tool
505
+ * that is advertised but never injected is a hallucinated-call generator. Member data and
506
+ * workspace file reads are owner-conversation material with no use in a scheduled turn.
507
+ */
508
+ exports.SCHEDULED_TURN_BLOCKED_TOOLS = new Set([
509
+ // workspace file reads are an owner-conversation tool; no turn section instructs one
510
+ 'Read',
511
+ // every outbound channel, not only Telegram: the grant is derived from the owner's
512
+ // (editable) role config, so a send tool added there must still never run unattended
513
+ 'telegram_send',
514
+ 'discord_send',
515
+ 'slack_send',
516
+ 'webchat_send',
517
+ 'drive_upload',
518
+ 'drive_list_drives',
519
+ 'drive_browse',
520
+ 'drive_find_folder',
521
+ 'drive_download',
522
+ 'ocr_image',
523
+ 'create_fb_overlay',
524
+ 'translate_conti',
525
+ 'drive_translate_conti',
526
+ 'member_candidates',
527
+ 'member_list',
528
+ 'member_scope_list',
529
+ ]);
530
+ /**
531
+ * Per-turn-kind blocked lists, projected by the HOST. One principal and one brief do
532
+ * not mean one grant for every trigger: an unattended board or wiki turn has no owner
533
+ * in the loop, so it never holds a send, an upload, or a mutation outside its own
534
+ * artifact. Each entry names the artifact it protects.
535
+ */
536
+ exports.TURN_KIND_BLOCKED_TOOLS = {
537
+ // board writes judgment slots and task lifecycle (reconcile mode creates rows for new
538
+ // items, which the action verifier's obligated set expects); it does not touch memory
539
+ // or the vault (obsidian is the wiki lane's write path)
540
+ board: new Set([
541
+ 'wiki_publish',
542
+ 'obsidian',
543
+ 'mama_save',
544
+ 'mama_update',
545
+ 'task_temporal_reconcile',
546
+ ]),
547
+ // wiki writes pages; the ledger, the board and memory are not its artifact
548
+ wiki: new Set([
549
+ 'report_publish',
550
+ 'mama_save',
551
+ 'mama_update',
552
+ 'task_create',
553
+ 'task_update',
554
+ 'task_temporal_reconcile',
555
+ ]),
556
+ // curation writes memory; nothing else
557
+ 'memory-curation': new Set([
558
+ 'report_publish',
559
+ 'wiki_publish',
560
+ 'task_create',
561
+ 'task_update',
562
+ 'task_temporal_reconcile',
563
+ 'obsidian',
564
+ ]),
565
+ // recheck resolves ONE task through task_temporal_reconcile; generic mutation is out
566
+ temporal: new Set([
567
+ 'report_publish',
568
+ 'wiki_publish',
569
+ 'mama_save',
570
+ 'mama_update',
571
+ 'task_create',
572
+ 'task_update',
573
+ 'obsidian',
574
+ ]),
498
575
  };
499
576
  /**
500
577
  * Packet-only reports receive no gateway tools. The host compiles current bounded authorities
@@ -563,27 +640,42 @@ function buildOperatorReportAgentPolicy(model, backend, privateConnectorPolicy)
563
640
  briefProjectionPolicy: requiredPrivatePolicy,
564
641
  };
565
642
  }
566
- function buildWorkOrderAgentPolicy(kind, model, backend, privateConnectorPolicy, rawConnectorScope) {
643
+ /** Outbound effect by name: sends to a channel or uploads to a shared store. */
644
+ function isOutboundToolName(tool) {
645
+ return /(^|_)(send|upload)(_|$)/.test(tool);
646
+ }
647
+ function buildTurnAgentPolicy(kind, model, backend, privateConnectorPolicy, rawConnectorScope, ownerRole = types_js_1.DEFAULT_ROLES.definitions.owner_console) {
567
648
  const requiredPrivatePolicy = requirePrivateConnectorPolicy(privateConnectorPolicy);
568
649
  if (!rawConnectorScope) {
569
650
  throw new Error('rawConnectorScope is required');
570
651
  }
571
- const policy = exports.WORKORDER_TOOL_POLICIES[kind];
572
- if (!policy) {
573
- throw new Error(`Missing built-in workorder tool policy for '${kind}'`);
652
+ const kindBlocked = exports.TURN_KIND_BLOCKED_TOOLS[kind];
653
+ if (!kindBlocked) {
654
+ throw new Error(`Missing turn-kind blocked list for '${kind}'`);
574
655
  }
575
- const surface = (0, private_connector_policy_js_1.resolveWorkOrderPrivateSurface)(kind);
656
+ // Same downgrade the event turn applies: a run with no private binding advertises
657
+ // no private connector tools and gets the disabled brief projection.
576
658
  const scopedSurface = requiredPrivatePolicy.enabledPrivateConnectors.some((name) => rawConnectorScope.includes(name))
577
- ? surface
659
+ ? exports.ONE_AGENT_TURN_POLICY.roleName
578
660
  : 'multi-agent-generic';
579
- const projectedRole = buildProjectedLaneRole(scopedSurface, policy.allowedTools, requiredPrivatePolicy);
580
- const blockedTools = [...(projectedRole.blockedTools ?? [])];
581
- const innerTools = uniqueToolList(projectedRole.allowedTools);
661
+ const blockedSet = new Set([
662
+ ...exports.ADMINISTRATION_TOOLS,
663
+ ...exports.SCHEDULED_TURN_BLOCKED_TOOLS,
664
+ ...kindBlocked,
665
+ ...(ownerRole.blockedTools ?? []),
666
+ // Shape rule on top of the named lists: the role config is owner-editable, so a
667
+ // send or upload tool that appears there tomorrow is still never unattended.
668
+ ...ownerRole.allowedTools.filter((tool) => isOutboundToolName(tool)),
669
+ ]);
670
+ const projectedRole = buildProjectedLaneRole(scopedSurface, uniqueToolList([...ownerRole.allowedTools, ...exports.TURN_KIND_REQUIRED_TOOLS[kind]]).filter((tool) => !blockedSet.has(tool)), requiredPrivatePolicy);
671
+ const blockedTools = [...new Set([...(projectedRole.blockedTools ?? []), ...blockedSet])];
672
+ // code_act is the transport, re-added at the front below; it is never an inner tool.
673
+ const innerTools = uniqueToolList(projectedRole.allowedTools).filter((tool) => !blockedSet.has(tool) && tool !== 'code_act');
582
674
  const allowedTools = uniqueToolList(['code_act', ...innerTools]);
583
675
  const agentContext = {
584
676
  source: 'operator',
585
677
  platform: 'cli',
586
- roleName: policy.roleName,
678
+ roleName: exports.ONE_AGENT_TURN_POLICY.roleName,
587
679
  role: { ...projectedRole, allowedTools, blockedTools, model },
588
680
  session: {
589
681
  sessionId: `operator:worker:${kind}`,
@@ -655,104 +747,27 @@ function buildSystemAgentProcessDefaults(config) {
655
747
  dangerouslySkipPermissions: config.multi_agent?.dangerouslySkipPermissions ?? true,
656
748
  };
657
749
  }
658
- const OWNER_BOARD_FULL_REPAIR_CHANNEL = 'host:owner-workorder:board-full';
659
- function buildOwnerEventBoardRefreshRuntime(operatorDb, taskLedger, now = Date.now) {
660
- const ownerEventBoardRefreshLedger = new owner_event_board_refresh_js_1.OwnerEventBoardRefreshLedger(operatorDb, taskLedger, now);
661
- const initialGeneration = (0, owner_event_board_refresh_js_1.resolveInitialBoardRepairGeneration)(now(), ownerEventBoardRefreshLedger.maxPendingGeneration());
662
- return {
663
- ownerEventBoardRefreshLedger,
664
- boardRefreshGate: new board_refresh_gate_js_1.BoardRefreshGate({ initialGeneration }),
665
- };
666
- }
667
750
  function resolveOwnerEventTerminalReceipt(batch, deps) {
668
- const confirmedEffects = deps.ownerEventEffectLedger.confirmedKinds(batch.id);
669
- if (confirmedEffects.length > 0) {
670
- return { status: 'acted', tools: confirmedEffects };
671
- }
672
- const acceptedWorkOrder = deps.ownerEventBoardRefreshLedger.findAcceptance(batch.id) ??
673
- deps.taskLedger.findWorkOrderByOccurrence('board', (0, workorder_publishers_js_1.boardBatchKey)(batch.eventIds)) ??
674
- deps.taskLedger.findWorkOrderByOccurrence('wiki', (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('wiki', batch.eventIds)) ??
675
- deps.taskLedger.findWorkOrderByOccurrence('memory-curation', (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('memory-curation', batch.eventIds));
676
- if (acceptedWorkOrder) {
677
- return { status: 'delegated', tools: ['workorder_request'] };
751
+ // Crash-recovery mirror of classifyOwnerEventOutcome. A ledger write that
752
+ // named this batch's events as its cause (evidence_effects) or a confirmed
753
+ // deliverable (drive_upload) is a durable outcome even if the run died after
754
+ // it - without this, a task created before a transport error is created again
755
+ // on retry. A confirmed telegram_send alone is not a receipt, and the effect
756
+ // ledger's (batch, action_key) idempotency makes that retry safe from a second
757
+ // send. A persisted Board acceptance is no longer a receipt.
758
+ const ledgerEffects = deps.taskLedger.effectsCausedBy(batch.eventIds, batch.createdAt);
759
+ const confirmedEffects = deps.ownerEventEffectLedger
760
+ .confirmedKinds(batch.id)
761
+ .filter((kind) => kind !== 'telegram_send');
762
+ const durable = [...new Set([...ledgerEffects, ...confirmedEffects])];
763
+ if (durable.length > 0) {
764
+ return { status: 'acted', tools: durable, ownerDecisionRequested: false };
678
765
  }
679
766
  if (deps.taskLedger.maxNoUpdateId(`owner-event:${batch.id}`) > 0) {
680
767
  return { status: 'no_update', tools: [] };
681
768
  }
682
769
  return null;
683
770
  }
684
- /** Build the enqueue-and-ack handler shared by owner chat and owner-event turns. */
685
- function buildOwnerWorkOrderRequestHandler(deps) {
686
- const now = deps.now ?? Date.now;
687
- const log = deps.log ?? ((line) => ownerWorkOrderLogger.info(line));
688
- const logError = deps.logError ?? ((line, detail) => ownerWorkOrderLogger.error(line, detail));
689
- return (kind, origin = { kind: 'owner_manual' }) => {
690
- try {
691
- const requestedAt = now();
692
- let idempotencyKey;
693
- let payload;
694
- if (kind === 'board') {
695
- if (!deps.boardRefreshGate) {
696
- throw new Error('Board refresh gate is unavailable');
697
- }
698
- if (origin.kind === 'owner_event') {
699
- if (!deps.ownerEventBoardRefreshLedger) {
700
- throw new Error('Owner-event Board refresh ledger is unavailable');
701
- }
702
- const existing = deps.ownerEventBoardRefreshLedger.findAcceptance(origin.batchId);
703
- if (existing) {
704
- log(`[stage2] owner workorder already accepted: board#${existing.workOrderId}`);
705
- return { accepted: true };
706
- }
707
- deps.boardRefreshGate.markChannelDirty(OWNER_BOARD_FULL_REPAIR_CHANNEL);
708
- const accepted = deps.ownerEventBoardRefreshLedger.accept({
709
- batchId: origin.batchId,
710
- eventIds: origin.eventIds,
711
- repair: deps.boardRefreshGate.captureFullRepair(),
712
- });
713
- log(`[stage2] owner workorder accepted: board#${accepted.workOrderId}`);
714
- return { accepted: true };
715
- }
716
- // TG-06: host dirt is recorded before validation or enqueue can fail.
717
- // The fixed synthetic channel never trusts model/event identifiers.
718
- deps.boardRefreshGate.markChannelDirty(OWNER_BOARD_FULL_REPAIR_CHANNEL);
719
- const repair = deps.boardRefreshGate.captureFullRepair();
720
- idempotencyKey = (0, workorder_publishers_js_1.boardManualKey)(requestedAt);
721
- payload = { mode: 'full', force: true, ...repair };
722
- }
723
- else if (kind === 'wiki') {
724
- if (origin.kind === 'owner_event') {
725
- idempotencyKey = (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('wiki', origin.eventIds);
726
- payload = { batchId: idempotencyKey, events: [...origin.eventIds] };
727
- }
728
- else {
729
- idempotencyKey = (0, workorder_publishers_js_1.wikiBatchKey)('manual', requestedAt);
730
- payload = { batchId: `${requestedAt}-manual`, events: ['manual'] };
731
- }
732
- }
733
- else {
734
- idempotencyKey =
735
- origin.kind === 'owner_event'
736
- ? (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('memory-curation', origin.eventIds)
737
- : (0, workorder_publishers_js_1.promotionManualKey)(requestedAt);
738
- payload = { scheduledAt: new Date(requestedAt).toISOString() };
739
- }
740
- (0, workorder_publishers_js_1.validateWorkOrderPayload)(kind, payload);
741
- const wo = deps.taskLedger.enqueueWorkOrder({
742
- workKind: kind,
743
- idempotencyKey,
744
- input: payload,
745
- priority: 'high',
746
- });
747
- log(`[stage2] owner workorder enqueued: ${kind}#${wo.id}`);
748
- return { accepted: true };
749
- }
750
- catch (err) {
751
- logError(`[stage2] owner workorder enqueue failed (${kind}):`, err instanceof Error ? err.message : err);
752
- return { accepted: false, reason: 'enqueue-failed' };
753
- }
754
- };
755
- }
756
771
  /**
757
772
  * Execute start command
758
773
  */
@@ -864,8 +879,10 @@ async function runAgentLoop(config, options = {}) {
864
879
  const temporalStartup = (0, temporal_runtime_js_1.preflightTemporalStartup)(process.env);
865
880
  const runtimeBackend = requireRuntimeBackend(config.agent.backend);
866
881
  const { connectorConfigLoadResult, privateConnectorPolicy } = (0, connector_bootstrap_js_1.resolveRuntimeConnectorBootstrap)((0, config_loader_js_1.loadConnectorConfig)());
882
+ // ONE owner role for every model turn: chat, event, and scheduled.
883
+ const ownerRole = config.roles?.definitions.owner_console ?? types_js_1.DEFAULT_ROLES.definitions.owner_console;
867
884
  const temporalPolicy = temporalStartup.temporalFlag === 'on'
868
- ? buildWorkOrderAgentPolicy('temporal', config.agent.model, runtimeBackend, privateConnectorPolicy, [])
885
+ ? buildTurnAgentPolicy('temporal', config.agent.model, runtimeBackend, privateConnectorPolicy, [], ownerRole)
869
886
  : null;
870
887
  const temporalEffectiveTools = temporalPolicy
871
888
  ? (0, tool_policy_js_1.projectCodeActToolPolicy)({
@@ -1316,7 +1333,9 @@ async function runAgentLoop(config, options = {}) {
1316
1333
  // delta reconcile scheduling; exact owner-event Board acceptance, boot
1317
1334
  // recovery, manual refresh, and full verification share this runtime in all
1318
1335
  // configurations.
1319
- const { ownerEventBoardRefreshLedger, boardRefreshGate } = buildOwnerEventBoardRefreshRuntime(operatorDb, taskLedger);
1336
+ // Host-owned Board repair gate. Generations are wall time: with the owner-event
1337
+ // intent ledger gone there is no persisted pending generation to seed above.
1338
+ const boardRefreshGate = new board_refresh_gate_js_1.BoardRefreshGate({ initialGeneration: Date.now() });
1320
1339
  const ownerEventEffectLedger = new owner_event_effects_js_1.OwnerEventEffectLedger(operatorDb);
1321
1340
  toolExecutor.setOwnerEventEffectLedger(ownerEventEffectLedger);
1322
1341
  let stopOwnerEventRuntime = null;
@@ -1366,6 +1385,10 @@ async function runAgentLoop(config, options = {}) {
1366
1385
  resolveWorkerRequestTimeoutMs();
1367
1386
  let workOrderConsumer = null;
1368
1387
  const boardRepairNudge = { current: null };
1388
+ const pipelineSlotPublisher = {
1389
+ current: null,
1390
+ };
1391
+ const learningBlockRef = { current: null };
1369
1392
  let temporalRuntime = null;
1370
1393
  gateways.push({
1371
1394
  stop: async () => {
@@ -1388,10 +1411,8 @@ async function runAgentLoop(config, options = {}) {
1388
1411
  });
1389
1412
  {
1390
1413
  const { WorkOrderConsumer } = await import('../../operator/workorder-consumer.js');
1391
- const { loadBrief, ensureBriefs } = await import('../../operator/briefs.js');
1392
- // Seed missing default briefs (user edits win) BEFORE the consumer exists -
1414
+ // Seed the ONE operating brief (user edits win) BEFORE the consumer exists -
1393
1415
  // a normal install must never hit the brief-missing fail path.
1394
- ensureBriefs();
1395
1416
  (0, console_brief_js_1.ensureConsoleBrief)();
1396
1417
  const { logActivity: logWorkOrderActivity } = await import('../../db/agent-store.js');
1397
1418
  // Ops alarm sink (plan D4/E1/G8): constructed OUTSIDE any trigger-loop
@@ -1423,7 +1444,42 @@ async function runAgentLoop(config, options = {}) {
1423
1444
  workOrderConsumer = new WorkOrderConsumer({
1424
1445
  ledger: taskLedger,
1425
1446
  runner: workerRunner,
1426
- loadBrief: (kind) => loadBrief(kind),
1447
+ loadOwnerBrief: () => (0, console_brief_js_1.loadConsoleBrief)(),
1448
+ // Host-rendered pipeline: the ledger's own deadline_priority page, published through
1449
+ // the SAME report publisher report_publish uses (bound after the API routes exist).
1450
+ buildLearningBlock: async (wo) => {
1451
+ const build = learningBlockRef.current;
1452
+ if (!build) {
1453
+ return '';
1454
+ }
1455
+ const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
1456
+ // Same binding the run's envelope gets: a recheck's lessons live under its task's channel.
1457
+ const temporalBinding = wo.workKind === 'temporal'
1458
+ ? temporalTaskBinding(taskLedger, (0, temporal_worker_js_1.buildTemporalWorkerContext)(taskLedger, wo).taskId)
1459
+ : null;
1460
+ const scope = workOrderEnvelopeScope({
1461
+ workKind: wo.workKind,
1462
+ projectId,
1463
+ laneConnectors: codeActRawConnectors,
1464
+ temporalBinding,
1465
+ reconcileChannelKey: wo.workKind === 'board' && typeof wo.payload.channelKey === 'string'
1466
+ ? wo.payload.channelKey
1467
+ : null,
1468
+ privateConnectorPolicy,
1469
+ });
1470
+ return build(wo.workKind, scope.memory_scopes, wo.workKind);
1471
+ },
1472
+ publishPipelineSlot: () => {
1473
+ const publish = pipelineSlotPublisher.current;
1474
+ if (!publish)
1475
+ throw new Error('pipeline slot publisher is not bound yet');
1476
+ const page = taskLedger.listPage({
1477
+ includeTerminal: false,
1478
+ order: 'deadline_priority',
1479
+ limit: board_pipeline_render_js_1.PIPELINE_SLOT_ROWS,
1480
+ });
1481
+ publish({ pipeline: (0, board_pipeline_render_js_1.renderPipelineSlot)(page.tasks, Date.now(), page.total) });
1482
+ },
1427
1483
  noticeOwner: (summary) => messageRouter.enqueueOperatorNotice(summary),
1428
1484
  opsAlarm,
1429
1485
  runOptionsFor: async (wo) => {
@@ -1439,11 +1495,17 @@ async function runAgentLoop(config, options = {}) {
1439
1495
  temporalBinding = temporalTaskBinding(taskLedger, temporalContext.taskId);
1440
1496
  }
1441
1497
  const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
1498
+ const reconcileChannelKey = wo.workKind === 'board' &&
1499
+ wo.payload.mode === 'reconcile' &&
1500
+ typeof wo.payload.channelKey === 'string'
1501
+ ? wo.payload.channelKey
1502
+ : null;
1442
1503
  const workOrderScope = workOrderEnvelopeScope({
1443
1504
  workKind: wo.workKind,
1444
1505
  projectId,
1445
1506
  laneConnectors: codeActRawConnectors,
1446
1507
  temporalBinding,
1508
+ reconcileChannelKey,
1447
1509
  privateConnectorPolicy,
1448
1510
  });
1449
1511
  // Worker prompt selects the provider's supported tool path: Claude's
@@ -1451,7 +1513,7 @@ async function runAgentLoop(config, options = {}) {
1451
1513
  // spawn-default code-act path, where per-run envelope/capture overrides
1452
1514
  // cannot reach (shadow-gate §8.2).
1453
1515
  const { buildWorkerSystemPrompt } = await import('../../operator/worker-run.js');
1454
- const workOrderPolicy = buildWorkOrderAgentPolicy(wo.workKind, config.agent.model, runtimeBackend, privateConnectorPolicy, workOrderScope.raw_connectors);
1516
+ const workOrderPolicy = buildTurnAgentPolicy(wo.workKind, config.agent.model, runtimeBackend, privateConnectorPolicy, workOrderScope.raw_connectors, ownerRole);
1455
1517
  const runOptions = attachWorkOrderAttemptContext({
1456
1518
  systemPrompt: buildWorkerSystemPrompt(workOrderPolicy.gatewayToolsPrompt, runtimeBackend, wo.workKind),
1457
1519
  agentContext: workOrderPolicy.agentContext,
@@ -1489,7 +1551,7 @@ async function runAgentLoop(config, options = {}) {
1489
1551
  if (envelopeBootstrap.envelopeAuthority && envelopeBootstrap.metadata.issuance !== 'off') {
1490
1552
  const wallSeconds = Math.min(Math.max(Number(process.env.MAMA_REPORT_WALL_SECONDS) || 900, 60), 1800);
1491
1553
  runOptions.envelope = await envelopeBootstrap.envelopeAuthority.buildAndPersist({
1492
- agent_id: `workorder-${wo.workKind}`,
1554
+ agent_id: 'mama-owner',
1493
1555
  instance_id: (0, node_crypto_1.randomUUID)(),
1494
1556
  // 'watch' = daemon-internal issuing source (closed EnvelopeSource
1495
1557
  // union; enforcement authorizes on scope, never on source).
@@ -1511,7 +1573,7 @@ async function runAgentLoop(config, options = {}) {
1511
1573
  // keeps the operational trace queryable.
1512
1574
  try {
1513
1575
  logWorkOrderActivity(db, {
1514
- agent_id: `workorder-${event.workKind}`,
1576
+ agent_id: 'mama-owner',
1515
1577
  agent_version: 0,
1516
1578
  type: `workorder_${event.type}`,
1517
1579
  input_summary: `#${event.workOrderId}`,
@@ -1528,21 +1590,9 @@ async function runAgentLoop(config, options = {}) {
1528
1590
  catch {
1529
1591
  /* telemetry only */
1530
1592
  }
1531
- if (event.type === 'complete' &&
1532
- event.workKind === 'board' &&
1533
- ownerEventBoardRefreshLedger.consumePostTerminalFollowup(event.workOrderId)) {
1534
- boardRepairNudge.current?.();
1535
- }
1536
1593
  },
1537
1594
  });
1538
1595
  // (Consumer stop is folded into the operator-DB gateway above - ordering.)
1539
- // Owner-issued workorders (workorder_request tool): enqueue+ack only.
1540
- // Wired here - NOT inside any trigger-loop block (plan C11 class).
1541
- toolExecutor.setWorkOrderRequestHandler(buildOwnerWorkOrderRequestHandler({
1542
- taskLedger,
1543
- boardRefreshGate,
1544
- ownerEventBoardRefreshLedger,
1545
- }));
1546
1596
  }
1547
1597
  const temporalTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
1548
1598
  const temporalAssembly = (0, temporal_init_js_1.assembleDaemonTemporalRuntime)({
@@ -1571,6 +1621,25 @@ async function runAgentLoop(config, options = {}) {
1571
1621
  if (connectorSchedulerStop) {
1572
1622
  gateways.push({ stop: () => Promise.resolve(connectorSchedulerStop()) });
1573
1623
  }
1624
+ // Owner policy and lessons: bound BEFORE the consumer starts (bootAfterRoutes) and
1625
+ // independent of the trigger loop, so scheduled turns carry the block even when
1626
+ // MAMA_TRIGGER_LOOP=0.
1627
+ // Owner policy and lessons for a turn: one bounded read path for event, scheduled
1628
+ // and (via MamaApiClient) chat turns. Returns the rendered block or ''.
1629
+ const learningReader = (0, learning_read_js_1.cappedLearningReader)((params) => mamaCore.queryRelevantTruth({ query: params.query, scopes: params.scopes }), (line) => console.log(line));
1630
+ const buildLearningBlockFor = async (turn, scopes, query) => {
1631
+ try {
1632
+ const context = await (0, learning_context_js_1.buildLearningContext)({ scopes, query, readClaims: learningReader });
1633
+ const channelScopeId = scopes.find((scope) => scope.kind === 'channel')?.id ?? null;
1634
+ console.log((0, learning_context_js_1.formatLearningAuditLine)(turn, channelScopeId, context));
1635
+ return context.promptBlock;
1636
+ }
1637
+ catch (error) {
1638
+ console.error(`[learning] ${turn} block failed: ${error instanceof Error ? error.message : String(error)}`);
1639
+ return '';
1640
+ }
1641
+ };
1642
+ learningBlockRef.current = buildLearningBlockFor;
1574
1643
  // ── Trigger loop (M1, default-on): agent-evolved triggers on the live stream ──
1575
1644
  // MAMA_TRIGGER_LOOP=0 is the explicit opt-out. Placed after initConnectors (which feeds
1576
1645
  // connector_event_index) and after mama-core initDB. Read-only: recall/surface/log.
@@ -1661,6 +1730,21 @@ async function runAgentLoop(config, options = {}) {
1661
1730
  issuance: envelopeBootstrap.metadata.issuance,
1662
1731
  hasAuthority: ownerEventEnvelopeAuthority !== undefined,
1663
1732
  });
1733
+ // Scope-independent packet readers, shared by the report leg and the event turn.
1734
+ const reportContextDeps = {
1735
+ listTaskPage: (input) => taskLedger.listPage(input),
1736
+ readClaims: (scope) => mamaCore.queryRelevantTruth({ query: '', scopes: scope.memoryScopes }),
1737
+ readTrello: async (scope) => {
1738
+ if (!scope.rawConnectors.includes('trello')) {
1739
+ throw new Error('Trello is outside the owner-report read scope');
1740
+ }
1741
+ return (0, query_tools_js_1.getTrelloKanban)({ maxCardsPerList: 100 });
1742
+ },
1743
+ buildProvenanceLookup: provenance_lookup_js_1.buildProvenanceLookup,
1744
+ correlate: external_correlation_js_1.correlateTasksWithExternalItems,
1745
+ readChanges: (_scope, input, nowMs) => (0, changes_projection_js_1.readChanges)(taskLedger, input, nowMs),
1746
+ now: Date.now,
1747
+ };
1664
1748
  const triggerLoop = new OperatorTriggerLoop({
1665
1749
  backend: runtimeBackend,
1666
1750
  delta: new ConnectorDeltaRepo(getAdapter(), (0, config_manager_js_1.expandPath)('~/.mama/operator/trigger-loop-cursors.json')),
@@ -1726,20 +1810,7 @@ async function runAgentLoop(config, options = {}) {
1726
1810
  ],
1727
1811
  };
1728
1812
  })(),
1729
- compileFullReportContext: async ({ readScope, windowEvidence, since }) => (0, report_context_js_1.compileOwnerReportContext)({ readScope, windowEvidence, since }, {
1730
- listTaskPage: (input) => taskLedger.listPage(input),
1731
- readClaims: (scope) => mamaCore.queryRelevantTruth({ query: '', scopes: scope.memoryScopes }),
1732
- readTrello: async (scope) => {
1733
- if (!scope.rawConnectors.includes('trello')) {
1734
- throw new Error('Trello is outside the owner-report read scope');
1735
- }
1736
- return (0, query_tools_js_1.getTrelloKanban)({ maxCardsPerList: 100 });
1737
- },
1738
- buildProvenanceLookup: provenance_lookup_js_1.buildProvenanceLookup,
1739
- correlate: external_correlation_js_1.correlateTasksWithExternalItems,
1740
- readChanges: (_scope, input, nowMs) => (0, changes_projection_js_1.readChanges)(taskLedger, input, nowMs),
1741
- now: Date.now,
1742
- }),
1813
+ compileFullReportContext: async ({ readScope, windowEvidence, since }) => (0, report_context_js_1.compileOwnerReportContext)({ readScope, windowEvidence, since }, reportContextDeps),
1743
1814
  // TG-06: composition supplies provenance immediately to the prepared
1744
1815
  // delivery; this callback receives that durable artifact only after send success.
1745
1816
  fullReportProvenance: () => lastReportProvenance,
@@ -1792,7 +1863,6 @@ async function runAgentLoop(config, options = {}) {
1792
1863
  // MAMA itself owns connector events. This is the same AgentLoop and
1793
1864
  // owner operating policy as the owner console, on a durable per-channel
1794
1865
  // background session. There is no separate Conductor persona.
1795
- const ownerRole = config.roles?.definitions.owner_console ?? types_js_1.DEFAULT_ROLES.definitions.owner_console;
1796
1866
  const ownerEventContext = (0, owner_event_policy_js_1.buildOwnerEventAgentContext)({
1797
1867
  backend: runtimeBackend,
1798
1868
  model: config.agent.model,
@@ -1800,8 +1870,24 @@ async function runAgentLoop(config, options = {}) {
1800
1870
  privateConnectorPolicy,
1801
1871
  });
1802
1872
  const ownerEventPromptEnhancer = new prompt_enhancer_js_1.PromptEnhancer();
1803
- const ownerEventIssueEnvelope = async (batch) => {
1873
+ // ONE expression for what an event turn may read: the envelope and the
1874
+ // packet are both built from it, so they can never disagree.
1875
+ const ownerEventReadScope = (batch) => {
1804
1876
  const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
1877
+ return {
1878
+ projectRefs: [{ kind: 'project', id: projectId }],
1879
+ rawConnectors: [
1880
+ ...privateConnectorPolicy.projectRawConnectors('owner_console', codeActRawConnectors),
1881
+ ],
1882
+ memoryScopes: uniqueMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
1883
+ source: 'owner-event',
1884
+ channelId: batch.channelKey,
1885
+ projectId,
1886
+ })),
1887
+ };
1888
+ };
1889
+ const ownerEventIssueEnvelope = async (batch) => {
1890
+ const readScope = ownerEventReadScope(batch);
1805
1891
  const wallSeconds = 300;
1806
1892
  return ownerEventEnvelopeAuthority.buildAndPersist({
1807
1893
  agent_id: 'mama-owner',
@@ -1810,15 +1896,9 @@ async function runAgentLoop(config, options = {}) {
1810
1896
  channel_id: batch.channelKey,
1811
1897
  trigger_context: { user_text: '<MAMA owner event turn>' },
1812
1898
  scope: {
1813
- project_refs: [{ kind: 'project', id: projectId }],
1814
- raw_connectors: [
1815
- ...privateConnectorPolicy.projectRawConnectors('owner_console', codeActRawConnectors),
1816
- ],
1817
- memory_scopes: uniqueMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
1818
- source: 'owner-event',
1819
- channelId: batch.channelKey,
1820
- projectId,
1821
- })),
1899
+ project_refs: readScope.projectRefs,
1900
+ raw_connectors: readScope.rawConnectors,
1901
+ memory_scopes: readScope.memoryScopes,
1822
1902
  allowed_destinations: reportChatId
1823
1903
  ? [{ kind: 'telegram', id: reportChatId }]
1824
1904
  : [],
@@ -1832,8 +1912,16 @@ async function runAgentLoop(config, options = {}) {
1832
1912
  inbox: ownerEventInbox,
1833
1913
  runner: agentLoop,
1834
1914
  agentContext: ownerEventContext,
1835
- buildPrompt: async (batch) => (0, owner_event_prompt_js_1.buildOwnerEventPrompt)({
1915
+ compilePacket: async (batch) => (0, report_context_js_1.serializeOwnerReportContext)(await (0, report_context_js_1.compileChannelPacket)({
1916
+ readScope: ownerEventReadScope(batch),
1917
+ channelKey: batch.channelKey,
1918
+ eventIds: batch.eventIds,
1919
+ since: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
1920
+ }, reportContextDeps)),
1921
+ buildPrompt: async (batch, packet) => (0, owner_event_prompt_js_1.buildOwnerEventPrompt)({
1836
1922
  batch,
1923
+ packet,
1924
+ learning: await buildLearningBlockFor('event', ownerEventReadScope(batch).memoryScopes, batch.lines.join('\n').slice(0, 500)),
1837
1925
  ownerBrief: (0, console_brief_js_1.projectConsoleBriefForPrompt)((0, console_brief_js_1.loadConsoleBrief)(), privateConnectorPolicy),
1838
1926
  skillContent: await ownerEventPromptEnhancer.detectSkillMatch(batch.lines.join('\n')),
1839
1927
  ownerTelegramChatId: reportChatId,
@@ -1842,7 +1930,6 @@ async function runAgentLoop(config, options = {}) {
1842
1930
  getNoUpdateMaxId: (scope) => taskLedger.maxNoUpdateId(scope),
1843
1931
  getTerminalReceipt: (batch) => resolveOwnerEventTerminalReceipt(batch, {
1844
1932
  ownerEventEffectLedger,
1845
- ownerEventBoardRefreshLedger,
1846
1933
  taskLedger,
1847
1934
  }),
1848
1935
  recordTriggerOutcome: (triggerId, outcome) => triggerRegistry.recordOutcome(triggerId, outcome),
@@ -1926,15 +2013,18 @@ async function runAgentLoop(config, options = {}) {
1926
2013
  getAdapter,
1927
2014
  privateConnectorPolicy,
1928
2015
  rawConnectorScope: [
1929
- ...privateConnectorPolicy.projectRawConnectors('workorder-board', codeActRawConnectors),
2016
+ ...privateConnectorPolicy.projectRawConnectors(exports.ONE_AGENT_TURN_POLICY.roleName, codeActRawConnectors),
1930
2017
  ],
1931
2018
  sessionsDb: db,
1932
2019
  workOrderConsumer: workOrderConsumer ?? undefined,
1933
2020
  boardRefreshGate,
1934
- ownerEventBoardRefreshLedger,
1935
2021
  requestFullReport: () => triggerLoopFullReport.current?.() ?? { accepted: false, reason: 'unavailable' },
1936
2022
  });
1937
2023
  boardRepairNudge.current = apiRoutesHandle.requestBoardRepair;
2024
+ {
2025
+ const { createReportPublisher } = await import('../../api/report-handler.js');
2026
+ pipelineSlotPublisher.current = createReportPublisher(apiServer.reportStore, apiServer.reportSseClients);
2027
+ }
1938
2028
  gateways.push({ stop: async () => apiRoutesHandle.stop() });
1939
2029
  // ── Stage-2 boot pass (plan S2-T3): runtime assembly registered hooks;
1940
2030
  // recovery/cleanup run after routes are ready, then the consumer starts.