@kienntpixon/dieu-phoi 0.6.1 → 0.7.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.
package/lib/aggregate.cjs CHANGED
@@ -56,13 +56,14 @@ function round6(v) {
56
56
 
57
57
  /**
58
58
  * Normalize a verdict to the two-layer model. Legacy `rework` (no `by`) = user reject/quality;
59
- * missing `by` otherwise = agent layer.
59
+ * missing `by` otherwise = agent layer. Core 0.7.0: `by=auto` (fast-mode self-acceptance) is its own layer —
60
+ * never a user verdict, never an agent verdict (CONTRACT "Mode theo yêu cầu").
60
61
  */
61
62
  function normalizeVerdict(ev) {
62
63
  if (ev.outcome === 'rework' && !ev.by) {
63
64
  return { by: 'user', outcome: 'reject', cause: 'quality', round: Number(ev.round) || null };
64
65
  }
65
- const by = ev.by === 'user' ? 'user' : 'agent';
66
+ const by = ev.by === 'user' ? 'user' : (ev.by === 'auto' ? 'auto' : 'agent');
66
67
  let cause = ev.cause || null;
67
68
  if (by === 'user' && ev.outcome === 'reject' && cause !== 'scope') cause = 'quality';
68
69
  let outcome = ev.outcome;
@@ -111,12 +112,18 @@ function steerIdOf(ev) {
111
112
  return typeof ev.steer_id === 'string' && ev.steer_id ? ev.steer_id : `${ev.agent_id}|${ev.ts}`;
112
113
  }
113
114
 
115
+ /** core 0.7.0: an exec's own selective-test verdict (`verify=self`) is not evidence for the agent layer. */
116
+ function isSelf(v) {
117
+ return !!v && v.verify === 'self';
118
+ }
119
+
114
120
  /**
115
- * Join events. Returns agents (one per real agent), userVerdicts (task layer), overrides, steers.
121
+ * Join events. Returns agents (one per real agent), userVerdicts (task layer), autoVerdicts (by=auto), overrides, steers.
116
122
  */
117
123
  function buildAgents(events) {
118
124
  const map = new Map();
119
125
  const userVerdicts = [];
126
+ const autoVerdicts = [];
120
127
  const overrides = [];
121
128
  const steers = [];
122
129
  const get = (id) => {
@@ -132,6 +139,7 @@ function buildAgents(events) {
132
139
  if (ev.kind === 'verdict') {
133
140
  const v = Object.assign(e, normalizeVerdict(ev));
134
141
  if (v.by === 'user') { userVerdicts.push(v); return; }
142
+ if (v.by === 'auto') { autoVerdicts.push(v); return; }
135
143
  }
136
144
  if (ev.kind === 'steer') steers.push(e);
137
145
  if (typeof ev.agent_id !== 'string' || !ev.agent_id) return;
@@ -149,6 +157,8 @@ function buildAgents(events) {
149
157
  const vAll = a.verdicts.slice().sort((x, y) => tsOf(x) - tsOf(y) || x._idx - y._idx);
150
158
  // `aborted` (quota pause) is neither pass nor fail: it never sets the outcome nor counts as a result.
151
159
  const v = vAll.filter((x) => x.outcome !== ABORTED);
160
+ const checked = v.filter((x) => !isSelf(x));
161
+ const selfs = v.filter(isSelf);
152
162
  const verdict = v.length ? v[v.length - 1] : null;
153
163
  const firstVerdictTs = v.length ? tsOf(v[0]) : Infinity;
154
164
  const pick = (k) => (d[k] !== undefined && d[k] !== null ? d[k] : (c0[k] !== undefined && c0[k] !== null ? c0[k] : null));
@@ -173,7 +183,10 @@ function buildAgents(events) {
173
183
  duration_s: a.completes.length ? sumOrNull(a.completes.map((x) => x.duration_s)) : null,
174
184
  tool_uses: a.completes.length ? sumOrNull(a.completes.map((x) => x.tool_uses)) : null,
175
185
  outcome: verdict ? verdict.outcome : null,
176
- first_outcome: v.length ? v[0].outcome : null,
186
+ // agent layer = first verdict that is not the exec's own selective tests (verify=self, core 0.7.0)
187
+ first_outcome: checked.length ? checked[0].outcome : null,
188
+ self_first: selfs.length ? selfs[0].outcome : null,
189
+ self_verdicts: selfs.length,
177
190
  // every non-aborted agent verdict in time order: a retry by SendMessage to the same agent is a new result
178
191
  verdict_seq: v.map((x) => ({ outcome: x.outcome, ts: tsOf(x), idx: x._idx })),
179
192
  aborted: vAll.length > 0 && vAll[vAll.length - 1].outcome === ABORTED,
@@ -187,24 +200,28 @@ function buildAgents(events) {
187
200
  last_complete_ts: a.completes.length ? Math.max(...a.completes.map(tsOf)) : 0,
188
201
  });
189
202
  }
190
- return { agents, userVerdicts, overrides, steers };
203
+ return { agents, userVerdicts, autoVerdicts, overrides, steers };
191
204
  }
192
205
 
193
206
  /** Group agents into tasks (sample unit = task_id; agents without task_id are their own task). */
194
- function buildTasks(agents, userVerdicts) {
207
+ function buildTasks(agents, userVerdicts, autoVerdicts) {
195
208
  const map = new Map();
196
209
  const byAgent = new Map();
197
210
  for (const a of agents) {
198
211
  const key = a.task_id ? `task:${a.task_id}` : `agent:${a.agent_id}`;
199
- if (!map.has(key)) map.set(key, { key, task_id: a.task_id, agents: [], user: [] });
212
+ if (!map.has(key)) map.set(key, { key, task_id: a.task_id, agents: [], user: [], auto: [] });
200
213
  map.get(key).agents.push(a);
201
214
  byAgent.set(a.agent_id, key);
202
215
  }
216
+ for (const v of autoVerdicts || []) {
217
+ const t = v.task_id ? map.get(`task:${v.task_id}`) : null;
218
+ if (t) t.auto.push(v);
219
+ }
203
220
  for (const v of userVerdicts || []) {
204
221
  let key = v.task_id ? `task:${v.task_id}` : null;
205
222
  if (!key && v.agent_id) key = byAgent.get(v.agent_id) || null; // legacy rework without task_id
206
223
  if (!key) continue;
207
- if (!map.has(key)) map.set(key, { key, task_id: v.task_id, agents: [], user: [] });
224
+ if (!map.has(key)) map.set(key, { key, task_id: v.task_id, agents: [], user: [], auto: [] });
208
225
  map.get(key).user.push(v);
209
226
  }
210
227
  const tasks = [];
@@ -261,6 +278,10 @@ function buildTasks(agents, userVerdicts) {
261
278
  if (userOutcome === 'accept') { success = true; source = 'user'; } else if (userOutcome === 'reject_quality') { success = false; source = 'user'; } else if (!userOutcome && agentFirst !== null) {
262
279
  success = agentFirst; source = 'agent';
263
280
  }
281
+ // core 0.7.0: by=auto never decides success; a user reject after the first auto accept overturns it.
282
+ const autoTs = t.auto.filter((v) => v.outcome === 'accept').map(tsOf);
283
+ const autoAccept = autoTs.length > 0;
284
+ const autoOverturned = autoAccept && user.some((v) => v.outcome === 'reject' && tsOf(v) > Math.min(...autoTs));
264
285
  const lastUser = user[user.length - 1] || null;
265
286
  const accepted = lastUser ? lastUser.outcome === 'accept' : attempts.some((a) => a.outcome === 'pass');
266
287
  const costed = t.agents.filter((a) => a.completed || a.outcome);
@@ -283,6 +304,9 @@ function buildTasks(agents, userVerdicts) {
283
304
  excluded: !!(first && first.steered) || userOutcome === 'reject_scope',
284
305
  accepted,
285
306
  agent_first_pass: agentFirst,
307
+ self_first: firstRes ? firstRes.self_first : null,
308
+ auto_accept: autoAccept,
309
+ auto_overturned: autoOverturned,
286
310
  // agents with a verdict but no complete event (hook missed) make cost/time unknown (null)
287
311
  total_cost: sumOrNull(costed.map((a) => a.cost_usd)),
288
312
  total_time_s: sumOrNull(costed.map((a) => a.duration_s)),
@@ -309,11 +333,17 @@ function buildCells(tasks, opts) {
309
333
  if (!f) continue;
310
334
  const key = cellKey(t.task_type, f.model, f.effort);
311
335
  if (!cells.has(key)) {
312
- cells.set(key, { task_type: t.task_type, model: f.model, effort: f.effort, dispatched: 0, excluded: 0, tasks: [], agentTasks: [] });
336
+ cells.set(key, {
337
+ task_type: t.task_type, model: f.model, effort: f.effort, dispatched: 0, excluded: 0, tasks: [], agentTasks: [], selfTasks: [], verdicted: 0, auto: 0, overturned: 0,
338
+ });
313
339
  }
314
340
  const c = cells.get(key);
315
341
  c.dispatched++;
342
+ if (t.auto_accept) c.auto++;
343
+ if (t.auto_overturned) c.overturned++;
316
344
  if (t.excluded) { c.excluded++; continue; }
345
+ if (t.self_first) c.selfTasks.push(t);
346
+ if (t.self_first || t.agent_first_pass !== null) c.verdicted++;
317
347
  if (t.success !== null) c.tasks.push(t);
318
348
  if (t.agent_first_pass !== null) c.agentTasks.push(t);
319
349
  }
@@ -331,6 +361,9 @@ function buildCells(tasks, opts) {
331
361
  // score uses the time median, not the mean: waits for the user (gate 3, quota pauses) inflate the mean
332
362
  // 3-13x (retro 2026-10-18: art-gen sonnet mean 483 vs p50 37 min) and would flip priors to slower tiers.
333
363
  const timeP50 = percentile(timesMin, 0.5);
364
+ const notes = [];
365
+ if (n < MIN_N) notes.push('chưa đủ dữ liệu');
366
+ if (c.verdicted && c.selfTasks.length / c.verdicted > 0.5) notes.push('ít bằng chứng');
334
367
  out.push({
335
368
  task_type: c.task_type,
336
369
  model: c.model,
@@ -358,8 +391,12 @@ function buildCells(tasks, opts) {
358
391
  attempt_p50_min: percentile(attemptTimes, 0.5),
359
392
  attempt_p75_min: percentile(attemptTimes, 0.75),
360
393
  score: costMean === null && timeP50 === null ? null : round6((costMean || 0) + lambda * (timeP50 || 0)),
394
+ n_self: c.selfTasks.length,
395
+ self_pass: c.selfTasks.filter((t) => t.self_first === 'pass').length,
396
+ auto_accept: c.auto,
397
+ auto_overturned: c.overturned,
361
398
  enough: n >= MIN_N,
362
- note: n >= MIN_N ? '' : 'chưa đủ dữ liệu',
399
+ note: notes.join('; '),
363
400
  });
364
401
  }
365
402
  out.sort((a, b) => a.task_type.localeCompare(b.task_type)
@@ -485,16 +522,102 @@ function orchestrationSummary(events) {
485
522
  }
486
523
 
487
524
  function analyze(events, opts) {
488
- const { agents, userVerdicts, overrides, steers } = buildAgents(withoutDiscarded(events));
489
- const tasks = buildTasks(agents, userVerdicts);
525
+ const { agents, userVerdicts, autoVerdicts, overrides, steers } = buildAgents(withoutDiscarded(events));
526
+ const tasks = buildTasks(agents, userVerdicts, autoVerdicts);
490
527
  const cells = buildCells(tasks, opts);
491
528
  return {
492
- agents, tasks, cells, overrides, userVerdicts, steerEvents: steers, steers: buildSteers(tasks, steers, agents),
529
+ agents, tasks, cells, overrides, userVerdicts, autoVerdicts, steerEvents: steers, steers: buildSteers(tasks, steers, agents),
493
530
  orchestration: orchestrationSummary(events),
494
531
  };
495
532
  }
496
533
 
497
534
  module.exports = {
498
- MIN_N, FAIL_OUTCOMES, HEAVY_STEERS, ABORTED, QUOTA_REASON_RE, HANDOFF_REASON_RE, discardedTaskIds, withoutDiscarded, CANONICAL_CELL_FIELDS, normalizeVerdict, isInternalComplete, buildAgents, buildTasks,
535
+ MIN_N, FAIL_OUTCOMES, HEAVY_STEERS, ABORTED, QUOTA_REASON_RE, HANDOFF_REASON_RE, discardedTaskIds, withoutDiscarded, CANONICAL_CELL_FIELDS, normalizeVerdict, isSelf, isInternalComplete, buildAgents, buildTasks,
499
536
  buildCells, buildSteers, canonicalCells, orchestrationSummary, analyze, cellKey, mean, percentile, tsOf, steerIdOf,
500
537
  };
538
+
539
+ // ------------------------------------------------------------------ core 0.7.0 (s2): stats split by mode
540
+ //
541
+ // Kept apart from the canonical cells (not part of the CLI <-> sink parity yet). A task's mode = `mode` of its first
542
+ // exec dispatch; tasks dispatched before modes existed (no `mode`) count as normal.
543
+
544
+ const MODE_KEYS = ['fast', 'normal', 'strict'];
545
+ const NO_CATCH_VERIFY = new Set(['self', 'none']);
546
+
547
+ /**
548
+ * Per mode: tasks, verified_tasks (a verify agent ran), catch_rate (share of exec agent verdicts checked by something
549
+ * other than self/none that came back fail), self_verdicts, batch_verify_fails, user_verdict_tasks, rejects (quality),
550
+ * reject_rate, verify_min (minutes of verify agents), test_s (sum of complete.test_s over the task's agents),
551
+ * test_s_per_task, full_suite_runs. `events` = the same events given to analyze(); `tasks` = analyze().tasks.
552
+ */
553
+ function modeSummary(events, tasks) {
554
+ const evs = withoutDiscarded(events).filter(Boolean);
555
+ const dispatchMode = new Map();
556
+ const tests = new Map();
557
+ const verdicts = new Map();
558
+ for (const ev of evs) {
559
+ if (ev.kind === 'dispatch' && typeof ev.agent_id === 'string' && !dispatchMode.has(ev.agent_id)) dispatchMode.set(ev.agent_id, ev.mode);
560
+ if (ev.kind === 'complete' && typeof ev.agent_id === 'string') {
561
+ const t = tests.get(ev.agent_id) || { s: 0, timed: 0, full: 0 };
562
+ const s = finiteNum(ev.test_s);
563
+ if (s !== null) { t.s += s; t.timed++; }
564
+ t.full += finiteNum(ev.full_suite_runs) || 0;
565
+ tests.set(ev.agent_id, t);
566
+ }
567
+ if (ev.kind === 'verdict' && ev.by !== 'user' && typeof ev.agent_id === 'string') {
568
+ if (!verdicts.has(ev.agent_id)) verdicts.set(ev.agent_id, []);
569
+ verdicts.get(ev.agent_id).push(ev);
570
+ }
571
+ }
572
+ const out = {};
573
+ for (const m of MODE_KEYS) {
574
+ out[m] = {
575
+ tasks: 0, verified_tasks: 0, checked_verdicts: 0, caught: 0, catch_rate: null, self_verdicts: 0, batch_verify_fails: 0,
576
+ user_verdict_tasks: 0, rejects: 0, reject_rate: null, verify_min: 0, test_s: 0, test_timed_tasks: 0, test_s_per_task: null, full_suite_runs: 0,
577
+ };
578
+ }
579
+ for (const t of tasks || []) {
580
+ if (!t.first) continue;
581
+ const raw = dispatchMode.get(t.first.agent_id);
582
+ const r = out[MODE_KEYS.includes(raw) ? raw : 'normal'];
583
+ r.tasks++;
584
+ if (t.verifies.length) r.verified_tasks++;
585
+ for (const v of t.verifies) r.verify_min += (finiteNum(v.duration_s) || 0) / 60;
586
+ let ts = 0;
587
+ let timed = false;
588
+ for (const a of t.attempts.concat(t.verifies)) {
589
+ const x = tests.get(a.agent_id);
590
+ if (!x) continue;
591
+ if (x.timed) { ts += x.s; timed = true; }
592
+ r.full_suite_runs += x.full;
593
+ }
594
+ if (timed) { r.test_s += ts; r.test_timed_tasks++; }
595
+ for (const a of t.attempts) {
596
+ if (a.role !== 'exec') continue;
597
+ for (const v of verdicts.get(a.agent_id) || []) {
598
+ if (v.outcome === 'fail' && /^batch-verify(?:-|$)/.test(String(v.reason_code || ''))) r.batch_verify_fails++;
599
+ if (v.verify === 'self') r.self_verdicts++;
600
+ if (v.outcome !== 'pass' && v.outcome !== 'fail') continue;
601
+ if (NO_CATCH_VERIFY.has(v.verify || 'none')) continue;
602
+ r.checked_verdicts++;
603
+ if (v.outcome === 'fail') r.caught++;
604
+ }
605
+ }
606
+ if (t.user_verdicts.length) {
607
+ r.user_verdict_tasks++;
608
+ if (t.user_verdicts.some((v) => v.outcome === 'reject' && v.cause !== 'scope')) r.rejects++;
609
+ }
610
+ }
611
+ for (const m of MODE_KEYS) {
612
+ const r = out[m];
613
+ r.catch_rate = r.checked_verdicts ? round6(r.caught / r.checked_verdicts) : null;
614
+ r.reject_rate = r.user_verdict_tasks ? round6(r.rejects / r.user_verdict_tasks) : null;
615
+ r.verify_min = round6(r.verify_min);
616
+ r.test_s = round6(r.test_s);
617
+ r.test_s_per_task = r.test_timed_tasks ? round6(r.test_s / r.test_timed_tasks) : null;
618
+ }
619
+ return out;
620
+ }
621
+
622
+ module.exports.MODE_KEYS = MODE_KEYS;
623
+ module.exports.modeSummary = modeSummary;
package/lib/args.cjs CHANGED
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const core = require('../hook.cjs');
6
6
 
7
- const BOOLEAN_FLAGS = new Set(['json', 'help', 'h', 'purge', 'version', 'v', 'dry-run', 'no-sync', 'approve', 'yes', 'force', 'follow', 'remove', 'dirty', 'no-cache', 'untagged', 'no-knowledge', 'net', 'with-codebase-memory', 'cbm', 'allow-custom-source']);
7
+ const BOOLEAN_FLAGS = new Set(['json', 'help', 'h', 'purge', 'version', 'v', 'dry-run', 'no-sync', 'approve', 'yes', 'force', 'follow', 'remove', 'dirty', 'no-cache', 'untagged', 'no-knowledge', 'net', 'with-codebase-memory', 'cbm', 'allow-custom-source', 'auto']);
8
8
 
9
9
  /** Minimal argv parser: positionals, --k v, --k=v, boolean flags. */
10
10
  function parseArgs(argv) {
package/lib/choose.cjs CHANGED
@@ -334,10 +334,56 @@ function resolveTaskType(raw, profile) {
334
334
  return { type: t, known: false, mapped_from: null, warning: `loại "${t}" không có trong danh sách cố định (${list}) — chọn loại gần nhất hoặc hỏi người dùng` };
335
335
  }
336
336
 
337
+ // ------------------------------------------------------------------ verify plan (core 0.7.0, mode per request)
338
+
339
+ const VERIFY_PLANS = ['independent-blocking', 'independent-nonblocking', 'self+batch', 'spot'];
340
+ /** fast: highest score still allowed to drop its own blocking verifier (s<=6 self+batch, s7-8 independent-nonblocking). */
341
+ const FAST_SELF_MAX = 6;
342
+ const FAST_SOFT_MAX = 8;
343
+ /** strict: share of steps that also get a random Opus reviewer spot check. */
344
+ const STRICT_SPOT_RATE = 1 / 3;
345
+
346
+ /**
347
+ * How one exec step is checked, from the request mode and the step's rubric inputs.
348
+ * The safety floor is evaluated FIRST and wins in every mode: reversible=n, publish/deploy, verifiable=n, score>=9
349
+ * always get an independent blocking verifier. Only after that does the mode loosen (fast) or tighten (strict).
350
+ * opts: { mode, score, verifiable, reversible, publish, dependents, seed }
351
+ * Returns { verify_plan, verify_reason, verify_floor: string[], test_scope: 'selective'|'full' }.
352
+ */
353
+ function verifyPlanFor(opts) {
354
+ const mode = opts.mode || core.DEFAULT_MODE;
355
+ if (!core.MODES.includes(mode)) throw new Error(`--mode phải là ${core.MODES.join('|')}`);
356
+ const score = Number(opts.score);
357
+ const floor = [];
358
+ if (opts.reversible === false) floor.push('khó hoàn tác');
359
+ if (opts.publish === true) floor.push('publish/deploy');
360
+ if (opts.verifiable === false) floor.push('không kiểm chứng bằng máy');
361
+ if (score >= 9) floor.push(`score ${score}≥9`);
362
+ const out = (plan, reason, scope) => ({ verify_plan: plan, verify_reason: reason, verify_floor: floor, test_scope: scope });
363
+ if (floor.length) return out('independent-blocking', `sàn an toàn (${floor.join(', ')}) → verifier độc lập chặn bước, mọi mode`, 'full');
364
+ if (mode === 'fast') {
365
+ if (score <= FAST_SELF_MAX) {
366
+ return out('self+batch', `fast, s${score}≤${FAST_SELF_MAX}: exec tự kiểm (test chọn lọc theo file đổi, --verify self); verifier gộp chạy cả suite một lần trước cổng 3`, 'selective');
367
+ }
368
+ if (score <= FAST_SOFT_MAX) {
369
+ return opts.dependents === true
370
+ ? out('independent-blocking', `fast, s${score}: bước sau phụ thuộc (depends_on) vào bước này → verifier độc lập vẫn chặn`, 'full')
371
+ : out('independent-nonblocking', `fast, s${score}: verifier độc lập nhưng không chặn bước sau (không bước nào depends_on)`, 'full');
372
+ }
373
+ }
374
+ if (mode === 'strict') {
375
+ const u = makeRng(opts.seed === undefined || opts.seed === null || opts.seed === true ? undefined : `spot:${opts.seed}`)();
376
+ if (u < STRICT_SPOT_RATE) return out('spot', 'strict: verifier độc lập chặn + reviewer Opus kiểm ngẫu nhiên (1/3), luôn chạy cả suite', 'full');
377
+ return out('independent-blocking', 'strict: verifier độc lập chặn, luôn chạy cả suite', 'full');
378
+ }
379
+ return out('independent-blocking', `${mode}: verifier độc lập chặn bước`, 'full');
380
+ }
381
+
337
382
  // ------------------------------------------------------------------ choose
338
383
 
339
384
  /**
340
- * opts: { type, score, urgency, reversible, verifiable, role, seed, events, profile, taskId, override, pricing }
385
+ * opts: { type, score, urgency, reversible, verifiable, role, seed, events, profile, taskId, override, pricing,
386
+ * mode, publish, dependents } (mode/publish/dependents only drive verify_plan, never the tier)
341
387
  * Returns { action, model, model_id, effort, reason, explored, tier, budget_s, est_cost_usd,
342
388
  * est_time_min, est_source, profile_source, suggested_tier?, overridden? , fails?, tried? }.
343
389
  * Throws when an override goes below a safety floor or off the ladder.
@@ -368,6 +414,13 @@ function choose(opts) {
368
414
  }
369
415
  const reversible = opts.reversible !== false;
370
416
  const verifiable = opts.verifiable !== false;
417
+ if (opts.mode !== undefined && opts.mode !== null && !core.MODES.includes(opts.mode)) {
418
+ throw new Error(`--mode phải là ${core.MODES.join('|')} (nhận "${opts.mode}")`);
419
+ }
420
+ const mode = opts.mode || core.DEFAULT_MODE;
421
+ const vp = role === 'exec'
422
+ ? verifyPlanFor({ mode, score, verifiable, reversible, publish: opts.publish === true, dependents: opts.dependents === true, seed: opts.seed })
423
+ : null;
371
424
  const profile = opts.profile || loadProfile(null);
372
425
  const lambda = profile.lambda[urgency];
373
426
  const rng = makeRng(opts.seed);
@@ -436,6 +489,11 @@ function choose(opts) {
436
489
  tier: tierName(idx),
437
490
  role,
438
491
  task_type: type,
492
+ mode,
493
+ verify_plan: vp ? vp.verify_plan : null,
494
+ verify_reason: vp ? vp.verify_reason : null,
495
+ verify_floor: vp ? vp.verify_floor : null,
496
+ test_scope: vp ? vp.test_scope : null,
439
497
  budget_s: budgetFor(cell),
440
498
  }, estimateFor(idx, cell, opts.pricing), { profile_source: src },
441
499
  rt.mapped_from ? { mapped_from: rt.mapped_from } : {}, rt.warning ? { type_warning: rt.warning } : {}, extra || {});
@@ -535,5 +593,5 @@ module.exports = {
535
593
  DEFAULT_ORCH_CTX_SOFT_CAP,
536
594
  LADDER, DEFAULT_PRIORS, DEFAULT_LAMBDA, DEFAULT_TIME_CAP_MIN, ROUGH, tierIndex, tierName, parsePrior,
537
595
  parseTier, loadProfile, makeRng, betaSample, escalation, overridePrior, roughEstimate, choose, shortModel,
538
- TYPE_ALIASES, resolveTaskType,
596
+ TYPE_ALIASES, resolveTaskType, verifyPlanFor, VERIFY_PLANS,
539
597
  };