@caupulican/pi-adaptative 0.80.98 → 0.80.100

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 (50) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/core/agent-session.d.ts +27 -3
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +200 -11
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/foreground-envelope.d.ts +22 -0
  7. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -0
  8. package/dist/core/autonomy/foreground-envelope.js +65 -0
  9. package/dist/core/autonomy/foreground-envelope.js.map +1 -0
  10. package/dist/core/autonomy/status.d.ts +11 -0
  11. package/dist/core/autonomy/status.d.ts.map +1 -1
  12. package/dist/core/autonomy/status.js.map +1 -1
  13. package/dist/core/delegation/worker-actions.d.ts +50 -0
  14. package/dist/core/delegation/worker-actions.d.ts.map +1 -0
  15. package/dist/core/delegation/worker-actions.js +70 -0
  16. package/dist/core/delegation/worker-actions.js.map +1 -0
  17. package/dist/core/delegation/worker-runner.d.ts +9 -0
  18. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  19. package/dist/core/delegation/worker-runner.js +38 -4
  20. package/dist/core/delegation/worker-runner.js.map +1 -1
  21. package/dist/core/model-capability.d.ts +19 -0
  22. package/dist/core/model-capability.d.ts.map +1 -1
  23. package/dist/core/model-capability.js +19 -0
  24. package/dist/core/model-capability.js.map +1 -1
  25. package/dist/core/models/default-model-suggestions.d.ts +34 -0
  26. package/dist/core/models/default-model-suggestions.d.ts.map +1 -0
  27. package/dist/core/models/default-model-suggestions.js +58 -0
  28. package/dist/core/models/default-model-suggestions.js.map +1 -0
  29. package/dist/core/settings-manager.d.ts +3 -0
  30. package/dist/core/settings-manager.d.ts.map +1 -1
  31. package/dist/core/settings-manager.js +5 -0
  32. package/dist/core/settings-manager.js.map +1 -1
  33. package/dist/core/slash-commands.d.ts.map +1 -1
  34. package/dist/core/slash-commands.js +1 -1
  35. package/dist/core/slash-commands.js.map +1 -1
  36. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  37. package/dist/modes/interactive/components/settings-selector.js +20 -0
  38. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  39. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  40. package/dist/modes/interactive/interactive-mode.js +10 -1
  41. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  42. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  43. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  44. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  45. package/examples/extensions/sandbox/package-lock.json +2 -2
  46. package/examples/extensions/sandbox/package.json +1 -1
  47. package/examples/extensions/with-deps/package-lock.json +2 -2
  48. package/examples/extensions/with-deps/package.json +1 -1
  49. package/npm-shrinkwrap.json +12 -12
  50. package/package.json +4 -4
@@ -21,6 +21,7 @@ import { stripFrontmatter } from "../utils/frontmatter.js";
21
21
  import { resolvePath } from "../utils/paths.js";
22
22
  import { sleep } from "../utils/sleep.js";
23
23
  import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
24
+ import { buildForegroundEnvelope, formatForegroundEnvelopeObservation } from "./autonomy/foreground-envelope.js";
24
25
  import { evaluateToolGate } from "./autonomy/gates.js";
25
26
  import { LaneTracker } from "./autonomy/lane-tracker.js";
26
27
  import { appendLaneRecordSnapshot, getLaneRecordSnapshots } from "./autonomy/session-lane-record.js";
@@ -45,6 +46,7 @@ import { aggregateDailyUsageFromSessionFiles, aggregateDailyUsageFromSessionRoot
45
46
  import { downgradeReasoning, estimateTurnCostUsd, evaluateCostGuard } from "./cost-guard.js";
46
47
  import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
47
48
  import { appendWorkerResultSnapshot, getWorkerResultSnapshots } from "./delegation/session-worker-result.js";
49
+ import { applyWorkerActions } from "./delegation/worker-actions.js";
48
50
  import { runWorker } from "./delegation/worker-runner.js";
49
51
  import { exportSessionToHtml } from "./export-html/index.js";
50
52
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
@@ -68,7 +70,7 @@ import { FileStoreProvider } from "./memory/providers/file-store.js";
68
70
  import { TranscriptRecallProvider } from "./memory/providers/transcript-recall.js";
69
71
  import { compactToolResultDetailsForRetention } from "./message-retention.js";
70
72
  import { createCustomMessage } from "./messages.js";
71
- import { deriveModelCapabilityProfile, filterToolNamesForCapability, } from "./model-capability.js";
73
+ import { deriveModelCapabilityProfile, filterToolNamesForCapability, scaleContinuationBudgetsForCapability, } from "./model-capability.js";
72
74
  import { resolveCliModel, resolveProfileModelSettings } from "./model-resolver.js";
73
75
  import { collectModelRouterConfigDiagnostics } from "./model-router/config-diagnostics.js";
74
76
  import { classifyExecutorTurn } from "./model-router/executor-route.js";
@@ -149,6 +151,8 @@ function persistModelRouterDecision(sessionManager, decision) {
149
151
  /** Custom-entry type for G3 autonomy telemetry. Distinct from the router/lane record types so a
150
152
  * telemetry consumer can filter on it without decoding operational snapshots. */
151
153
  const AUTONOMY_TELEMETRY_CUSTOM_TYPE = "autonomy-telemetry";
154
+ /** G8: bound on the in-memory gate-outcome history. Oldest entries evict once the cap is reached. */
155
+ const GATE_OUTCOME_HISTORY_LIMIT = 50;
152
156
  /** Read a packed grep/find tool result's `details.artifactId`, if present, without `any`. */
153
157
  function extractArtifactId(message) {
154
158
  if (!message || message.role !== "toolResult")
@@ -218,8 +222,6 @@ export class AgentSession {
218
222
  _laneTracker = new LaneTracker();
219
223
  /** Session-lifetime abort for in-flight research passes (same pattern as _reflectionAbort). */
220
224
  _researchLaneAbort = new AbortController();
221
- /** Single-flight guard: at most one delegated worker runs at a time per session. */
222
- _isWorkerDelegationRunning = false;
223
225
  /** Session-lifetime abort for in-flight delegated workers. */
224
226
  _workerDelegationAbort = new AbortController();
225
227
  /**
@@ -258,6 +260,8 @@ export class AgentSession {
258
260
  // Extension system
259
261
  _extensionRunner;
260
262
  _turnIndex = 0;
263
+ /** G7: per-turn foreground CapabilityEnvelope auto-built for visibility (observe-only; not enforced). */
264
+ _currentForegroundEnvelope;
261
265
  _resourceLoader;
262
266
  _customTools;
263
267
  _baseToolDefinitions = new Map();
@@ -292,6 +296,8 @@ export class AgentSession {
292
296
  _isModelRouterRetry = false;
293
297
  _lastModelRouterDecision;
294
298
  _lastAutonomyGateOutcome;
299
+ /** G8: bounded (cap {@link GATE_OUTCOME_HISTORY_LIMIT}) history of gate outcomes; tail is latest. */
300
+ _gateOutcomeHistory = [];
295
301
  _lastModelRouterSkipReason;
296
302
  _lastModelRouterIntent;
297
303
  /** Lazily-built skill curator (#32) over `<agentDir>/skills`. */
@@ -1014,6 +1020,9 @@ export class AgentSession {
1014
1020
  ...this._resourceLoader.getAgentsDiagnostics().map((diagnostic) => diagnostic.message),
1015
1021
  ...this._inertExtensionWarnings,
1016
1022
  ...this._unboundToolGrantWarnings,
1023
+ // G7: auto-built per-turn foreground envelope (observe-only; not enforced). Falls back to a
1024
+ // live preview when no turn has run yet so /context always shows the current scope.
1025
+ formatForegroundEnvelopeObservation(this._currentForegroundEnvelope ?? this._buildForegroundEnvelopeFromState()),
1017
1026
  // G14 (ratified): a user disable always beats a profile grant — surface the conflict.
1018
1027
  ...["tools", "skills", "prompts", "extensions"].flatMap((kind) => this.settingsManager
1019
1028
  .getProfileGrantsOverriddenByUserDisable(kind)
@@ -1351,7 +1360,7 @@ export class AgentSession {
1351
1360
  envelope: this.capabilityEnvelope,
1352
1361
  });
1353
1362
  if (this.capabilityEnvelope) {
1354
- this._lastAutonomyGateOutcome = gateResult;
1363
+ this._recordGateOutcome(gateResult);
1355
1364
  }
1356
1365
  if (gateResult.outcome === "block" || gateResult.outcome === "ask-user") {
1357
1366
  return {
@@ -1568,6 +1577,7 @@ export class AgentSession {
1568
1577
  await this._extensionRunner.emit({ type: "agent_end", messages: event.messages });
1569
1578
  }
1570
1579
  else if (event.type === "turn_start") {
1580
+ this._refreshForegroundEnvelope();
1571
1581
  const extensionEvent = {
1572
1582
  type: "turn_start",
1573
1583
  turnIndex: this._turnIndex,
@@ -1789,6 +1799,31 @@ export class AgentSession {
1789
1799
  getActiveToolNames() {
1790
1800
  return this.agent.state.tools.map((t) => t.name);
1791
1801
  }
1802
+ /** G7: build a foreground {@link CapabilityEnvelope} from the live session state (active tools, cwd, cost ceiling). */
1803
+ _buildForegroundEnvelopeFromState() {
1804
+ return buildForegroundEnvelope({
1805
+ turnIndex: this._turnIndex,
1806
+ activeToolNames: this.getActiveToolNames(),
1807
+ cwd: this._cwd,
1808
+ maxTurnUsd: this.settingsManager.getCostGuardSettings().maxTurnUsd,
1809
+ });
1810
+ }
1811
+ /**
1812
+ * G7: (re)build the foreground envelope for the current turn. Visibility only -- the foreground
1813
+ * envelope is NOT enforced this round. Best-effort: never throws into the turn.
1814
+ */
1815
+ _refreshForegroundEnvelope() {
1816
+ try {
1817
+ this._currentForegroundEnvelope = this._buildForegroundEnvelopeFromState();
1818
+ }
1819
+ catch {
1820
+ // Visibility only: a failure to build the envelope must never disturb the turn.
1821
+ }
1822
+ }
1823
+ /** G7: the auto-constructed foreground envelope for the current/most-recent turn (visibility only). */
1824
+ getForegroundEnvelope() {
1825
+ return this._currentForegroundEnvelope;
1826
+ }
1792
1827
  /**
1793
1828
  * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.
1794
1829
  */
@@ -2092,6 +2127,59 @@ export class AgentSession {
2092
2127
  return undefined;
2093
2128
  }
2094
2129
  }
2130
+ /** True if a run_toolkit_script tool result since `fromIndex` actually EXECUTED (not error/ambiguous). */
2131
+ _executorTurnExecutedScript(fromIndex) {
2132
+ for (const message of this.agent.state.messages.slice(fromIndex)) {
2133
+ if (message.role !== "toolResult")
2134
+ continue;
2135
+ if (message.toolName !== "run_toolkit_script")
2136
+ continue;
2137
+ if (message.isError === true)
2138
+ continue;
2139
+ const outcome = message.details?.outcome;
2140
+ if (outcome === "executed")
2141
+ return true;
2142
+ }
2143
+ return false;
2144
+ }
2145
+ /** Ask the reflex brain to refine the last user request into an explicit toolkit instruction. */
2146
+ async _buildExecutorRefinedPrompt(messages) {
2147
+ try {
2148
+ const model = this._resolveCurationModelIfFit();
2149
+ if (!model)
2150
+ return undefined;
2151
+ const list = Array.isArray(messages) ? messages : [messages];
2152
+ const request = latestUserPromptText(list.filter((m) => true));
2153
+ if (!request)
2154
+ return undefined;
2155
+ const scripts = this.settingsManager.getToolkitScripts();
2156
+ const completion = await this.runIsolatedCompletion({
2157
+ systemPrompt: REFLEX_INTERPRETER_SYSTEM_PROMPT,
2158
+ messages: [
2159
+ {
2160
+ role: "user",
2161
+ content: [{ type: "text", text: buildReflexUserPrompt(request, scripts) }],
2162
+ timestamp: Date.now(),
2163
+ },
2164
+ ],
2165
+ model,
2166
+ thinkingLevel: "off",
2167
+ maxTokens: 256,
2168
+ cacheRetention: "short",
2169
+ });
2170
+ if (completion.usage.cost.total > 0 || completion.usage.totalTokens > 0) {
2171
+ this.addSpawnedUsage(completion.usage, { label: "executor-brain-warmup" });
2172
+ }
2173
+ const plan = parseReflexPlan(completion.text);
2174
+ if (!plan || plan.script === "none")
2175
+ return undefined;
2176
+ const argHint = plan.args.length > 0 ? ` with args ${JSON.stringify(plan.args)}` : "";
2177
+ return `Run the toolkit script "${plan.script}"${argHint} using run_toolkit_script, then report its result exactly.`;
2178
+ }
2179
+ catch {
2180
+ return undefined;
2181
+ }
2182
+ }
2095
2183
  _resolveModelRouterTurnRoute(prompt) {
2096
2184
  const settings = this.settingsManager.getModelRouterSettings();
2097
2185
  if (!settings.enabled) {
@@ -2328,6 +2416,36 @@ export class AgentSession {
2328
2416
  }
2329
2417
  try {
2330
2418
  await this._runAgentPrompt(messages);
2419
+ // Speculative muscle-retry (G16 refinement): an executor-routed turn is a bet that the
2420
+ // small model can run the toolkit command directly. If it ends WITHOUT a successful
2421
+ // run_toolkit_script execution, retry ONCE on the same executor with the brain's
2422
+ // refined instruction injected — the brain warms while the muscle tries, so the retry
2423
+ // pays only when the muscle actually missed.
2424
+ if (routeDecision?.reasonCode === "executor_direct" &&
2425
+ !this._isModelRouterRetry &&
2426
+ !this._executorTurnExecutedScript(originalHistoryLength)) {
2427
+ const refined = await this._buildExecutorRefinedPrompt(messages);
2428
+ if (refined) {
2429
+ this.agent.state.messages.splice(originalHistoryLength);
2430
+ await this._runAgentPrompt([
2431
+ { role: "user", content: [{ type: "text", text: refined }], timestamp: Date.now() },
2432
+ ]);
2433
+ completedDecision = {
2434
+ route: {
2435
+ ...routeDecision,
2436
+ reasonCode: "executor_speculative_retry",
2437
+ reasons: [
2438
+ ...routeDecision.reasons,
2439
+ "Executor missed on first try; retried with brain-refined instruction",
2440
+ ],
2441
+ },
2442
+ routedModel: formatModelRouterModel(routedModel),
2443
+ outcome: "routed",
2444
+ intent: "research",
2445
+ };
2446
+ this._lastModelRouterDecision = completedDecision;
2447
+ }
2448
+ }
2331
2449
  if (bufferRoutedTurn && this._modelRouterEscalationRequested) {
2332
2450
  this.agent.state.messages.splice(originalHistoryLength);
2333
2451
  retryModel = this._resolveModelRouterModelForIntent("modify") ?? previousModel;
@@ -5101,6 +5219,40 @@ export class AgentSession {
5101
5219
  // Telemetry is best-effort: swallow so a sink failure cannot break the observed turn.
5102
5220
  }
5103
5221
  }
5222
+ /**
5223
+ * G8: single sink for a gate outcome. Keeps the latest-outcome getter behavior identical (the
5224
+ * full {@link GateOutcome} still lands in `_lastAutonomyGateOutcome`), and additionally appends a
5225
+ * bounded codes-only entry to {@link _gateOutcomeHistory} (oldest evicted at
5226
+ * {@link GATE_OUTCOME_HISTORY_LIMIT}) and emits the `gate_outcome` telemetry event. The history
5227
+ * tail therefore always mirrors the latest outcome. Only called with an active envelope.
5228
+ */
5229
+ _recordGateOutcome(outcome) {
5230
+ this._lastAutonomyGateOutcome = outcome;
5231
+ const at = new Date().toISOString();
5232
+ this._gateOutcomeHistory.push({
5233
+ outcome: outcome.outcome,
5234
+ gate: outcome.gate,
5235
+ reasonCode: outcome.reasonCode,
5236
+ at,
5237
+ });
5238
+ while (this._gateOutcomeHistory.length > GATE_OUTCOME_HISTORY_LIMIT) {
5239
+ this._gateOutcomeHistory.shift();
5240
+ }
5241
+ // G8: gate outcome event. Codes/ids only — never the gate's human-facing message.
5242
+ this._emitAutonomyTelemetry({
5243
+ type: AUTONOMY_TELEMETRY_EVENT_TYPES.gateOutcome,
5244
+ timestamp: at,
5245
+ payload: {
5246
+ outcome: outcome.outcome,
5247
+ gate: outcome.gate,
5248
+ reasonCode: outcome.reasonCode,
5249
+ },
5250
+ });
5251
+ }
5252
+ /** G8: copies of the bounded gate-outcome history, oldest first, latest last. */
5253
+ getGateOutcomeHistory() {
5254
+ return this._gateOutcomeHistory.map((entry) => ({ ...entry }));
5255
+ }
5104
5256
  saveWorkerResultSnapshot(result, request) {
5105
5257
  return appendWorkerResultSnapshot(this.sessionManager, result, request);
5106
5258
  }
@@ -5157,12 +5309,17 @@ export class AgentSession {
5157
5309
  const snapshot = this.getGoalRuntimeSnapshot({ maxStallTurns });
5158
5310
  if (snapshot.continuation.action !== "continue")
5159
5311
  return;
5312
+ // Lean-window models (16-32k) keep autosteer but at a reduced budget; full passes through.
5313
+ const scaled = scaleContinuationBudgetsForCapability(this.getModelCapabilityProfile(), {
5314
+ maxTurns: goalContinueTurns,
5315
+ maxWallClockMinutes: goalContinueMaxWallClockMinutes,
5316
+ });
5160
5317
  this._isGoalAutoContinuing = true;
5161
5318
  try {
5162
5319
  await this.continueGoalLoop({
5163
- maxTurns: goalContinueTurns,
5320
+ maxTurns: scaled.maxTurns,
5164
5321
  maxStallTurns,
5165
- maxWallClockMinutes: goalContinueMaxWallClockMinutes,
5322
+ maxWallClockMinutes: scaled.maxWallClockMinutes,
5166
5323
  });
5167
5324
  }
5168
5325
  catch (error) {
@@ -5500,7 +5657,8 @@ export class AgentSession {
5500
5657
  * usage (idempotent per-lane reportId). Consumed by the `delegate` tool.
5501
5658
  */
5502
5659
  async runWorkerDelegationOnce(request) {
5503
- if (this._isWorkerDelegationRunning) {
5660
+ const delegationSettings = this.settingsManager.getWorkerDelegationSettings();
5661
+ if (this._laneTracker.getActiveCount("worker") >= delegationSettings.maxConcurrent) {
5504
5662
  return { started: false, skipReason: "worker_delegation_already_running" };
5505
5663
  }
5506
5664
  if (this._disposed) {
@@ -5510,7 +5668,7 @@ export class AgentSession {
5510
5668
  if (instructions.length === 0) {
5511
5669
  return { started: false, skipReason: "missing_instructions" };
5512
5670
  }
5513
- const settings = this.settingsManager.getWorkerDelegationSettings();
5671
+ const settings = delegationSettings;
5514
5672
  if (!settings.enabled) {
5515
5673
  return { started: false, skipReason: "worker_delegation_disabled" };
5516
5674
  }
@@ -5519,7 +5677,6 @@ export class AgentSession {
5519
5677
  return { started: false, skipReason: shipment.skipReason };
5520
5678
  }
5521
5679
  const { model, laneProfile } = shipment;
5522
- this._isWorkerDelegationRunning = true;
5523
5680
  this._laneTracker.ensureCounterAtLeast(getLaneRecordSnapshots(this.sessionManager.getEntries()).length + 1);
5524
5681
  const startedRecord = this._laneTracker.start({ type: "worker" });
5525
5682
  const maxUsd = Math.min(settings.maxUsd, this.capabilityEnvelope?.maxEstimatedUsd ?? Number.POSITIVE_INFINITY);
@@ -5536,7 +5693,12 @@ export class AgentSession {
5536
5693
  envelope: {
5537
5694
  id: `worker-${this.sessionId}-${startedRecord.laneId}`,
5538
5695
  profileId: laneProfile?.name,
5539
- capabilities: ["read_files"],
5696
+ // write_files requires BOTH the opt-in AND an explicit non-empty path scope —
5697
+ // an unscoped write grant is refused here, not discovered at validation time.
5698
+ capabilities: settings.writeEnabled && settings.writePaths.length > 0 ? ["read_files", "write_files"] : ["read_files"],
5699
+ ...(settings.writeEnabled && settings.writePaths.length > 0
5700
+ ? { allowedPaths: [...settings.writePaths] }
5701
+ : {}),
5540
5702
  ...this._laneProfileToolGrants(laneProfile),
5541
5703
  maxEstimatedUsd: maxUsd,
5542
5704
  createdAt: new Date().toISOString(),
@@ -5544,6 +5706,17 @@ export class AgentSession {
5544
5706
  maxEstimatedUsd: maxUsd,
5545
5707
  createdAt: new Date().toISOString(),
5546
5708
  };
5709
+ // G8: worker delegation START. Routing/scope codes + budget only — never the instructions text.
5710
+ this._emitAutonomyTelemetry({
5711
+ type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerRequest,
5712
+ timestamp: new Date().toISOString(),
5713
+ payload: {
5714
+ id: workerRequest.id,
5715
+ tier: workerRequest.route.tier,
5716
+ capabilities: [...workerRequest.envelope.capabilities],
5717
+ maxEstimatedUsd: workerRequest.maxEstimatedUsd ?? null,
5718
+ },
5719
+ });
5547
5720
  const usageReportId = `worker:${this.sessionId}:${startedRecord.laneId}`;
5548
5721
  try {
5549
5722
  let spentUsage;
@@ -5553,6 +5726,10 @@ export class AgentSession {
5553
5726
  maxWallClockMs: settings.maxWallClockMs,
5554
5727
  usageReportId,
5555
5728
  signal: this._workerDelegationAbort.signal,
5729
+ // Write lane (G2): runner-side action application through the envelope path scope.
5730
+ applyActions: workerRequest.envelope.capabilities.includes("write_files")
5731
+ ? (actions) => applyWorkerActions({ actions, envelope: workerRequest.envelope, cwd: this._cwd })
5732
+ : undefined,
5556
5733
  complete: async ({ systemPrompt, userPrompt, signal }) => {
5557
5734
  const completion = await this.runIsolatedCompletion({
5558
5735
  // Level-0 core always survives. A model-provided prompt (delegate tool) is the most
@@ -5637,7 +5814,6 @@ export class AgentSession {
5637
5814
  return { started: true, record };
5638
5815
  }
5639
5816
  finally {
5640
- this._isWorkerDelegationRunning = false;
5641
5817
  }
5642
5818
  }
5643
5819
  /**
@@ -5958,6 +6134,19 @@ export class AgentSession {
5958
6134
  requiresApproval: decision.requiresApproval,
5959
6135
  },
5960
6136
  });
6137
+ // G8: a proposal that needs human sign-off is an approval REQUEST. Codes/layer only —
6138
+ // never the proposal summary/memory text (those live only in the audit snapshot).
6139
+ if (decision.requiresApproval) {
6140
+ this._emitAutonomyTelemetry({
6141
+ type: AUTONOMY_TELEMETRY_EVENT_TYPES.approvalRequest,
6142
+ timestamp: new Date().toISOString(),
6143
+ payload: {
6144
+ kind: decision.kind,
6145
+ reasonCode: decision.reasonCode,
6146
+ layer: proposal.layer,
6147
+ },
6148
+ });
6149
+ }
5961
6150
  if (decision.kind === "apply") {
5962
6151
  await this._applyReflectionWrite(write, signal);
5963
6152
  }