@sellable/mcp 0.1.147 → 0.1.148
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/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/tools/registry.d.ts +7 -0
- package/dist/tools/rubrics.d.ts +55 -23
- package/dist/tools/rubrics.js +93 -10
- package/package.json +1 -1
- package/skills/create-campaign-v2/SKILL.md +4 -3
- package/skills/create-campaign-v2/core/flow.v2.json +13 -7
- package/skills/create-campaign-v2/references/sample-validation-loop.md +9 -5
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +12 -7
- package/skills/create-campaign-v2/references/watch-guide-narration.md +5 -4
- package/skills/create-campaign-v2-tail/SKILL.md +24 -16
- package/skills/research/config.json +9 -0
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -3702,6 +3702,7 @@ export declare const allTools: ({
|
|
|
3702
3702
|
tableId?: undefined;
|
|
3703
3703
|
targetCount?: undefined;
|
|
3704
3704
|
minPassedCount?: undefined;
|
|
3705
|
+
minMessagesCount?: undefined;
|
|
3705
3706
|
timeoutMs?: undefined;
|
|
3706
3707
|
intervalMs?: undefined;
|
|
3707
3708
|
includeRows?: undefined;
|
|
@@ -3735,6 +3736,7 @@ export declare const allTools: ({
|
|
|
3735
3736
|
tableId?: undefined;
|
|
3736
3737
|
targetCount?: undefined;
|
|
3737
3738
|
minPassedCount?: undefined;
|
|
3739
|
+
minMessagesCount?: undefined;
|
|
3738
3740
|
timeoutMs?: undefined;
|
|
3739
3741
|
intervalMs?: undefined;
|
|
3740
3742
|
includeRows?: undefined;
|
|
@@ -3793,6 +3795,7 @@ export declare const allTools: ({
|
|
|
3793
3795
|
tableId?: undefined;
|
|
3794
3796
|
targetCount?: undefined;
|
|
3795
3797
|
minPassedCount?: undefined;
|
|
3798
|
+
minMessagesCount?: undefined;
|
|
3796
3799
|
timeoutMs?: undefined;
|
|
3797
3800
|
intervalMs?: undefined;
|
|
3798
3801
|
includeRows?: undefined;
|
|
@@ -3851,6 +3854,7 @@ export declare const allTools: ({
|
|
|
3851
3854
|
tableId?: undefined;
|
|
3852
3855
|
targetCount?: undefined;
|
|
3853
3856
|
minPassedCount?: undefined;
|
|
3857
|
+
minMessagesCount?: undefined;
|
|
3854
3858
|
timeoutMs?: undefined;
|
|
3855
3859
|
intervalMs?: undefined;
|
|
3856
3860
|
includeRows?: undefined;
|
|
@@ -3911,6 +3915,7 @@ export declare const allTools: ({
|
|
|
3911
3915
|
tableId?: undefined;
|
|
3912
3916
|
targetCount?: undefined;
|
|
3913
3917
|
minPassedCount?: undefined;
|
|
3918
|
+
minMessagesCount?: undefined;
|
|
3914
3919
|
timeoutMs?: undefined;
|
|
3915
3920
|
intervalMs?: undefined;
|
|
3916
3921
|
includeRows?: undefined;
|
|
@@ -3941,6 +3946,7 @@ export declare const allTools: ({
|
|
|
3941
3946
|
tableId?: undefined;
|
|
3942
3947
|
targetCount?: undefined;
|
|
3943
3948
|
minPassedCount?: undefined;
|
|
3949
|
+
minMessagesCount?: undefined;
|
|
3944
3950
|
timeoutMs?: undefined;
|
|
3945
3951
|
intervalMs?: undefined;
|
|
3946
3952
|
includeRows?: undefined;
|
|
@@ -3971,6 +3977,7 @@ export declare const allTools: ({
|
|
|
3971
3977
|
tableId?: undefined;
|
|
3972
3978
|
targetCount?: undefined;
|
|
3973
3979
|
minPassedCount?: undefined;
|
|
3980
|
+
minMessagesCount?: undefined;
|
|
3974
3981
|
timeoutMs?: undefined;
|
|
3975
3982
|
intervalMs?: undefined;
|
|
3976
3983
|
includeRows?: undefined;
|
package/dist/tools/rubrics.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ type WaitForRubricResultsInput = {
|
|
|
33
33
|
tableId?: string;
|
|
34
34
|
targetCount?: number;
|
|
35
35
|
minPassedCount?: number;
|
|
36
|
+
minMessagesCount?: number;
|
|
36
37
|
timeoutMs?: number;
|
|
37
38
|
intervalMs?: number;
|
|
38
39
|
includeRows?: boolean;
|
|
@@ -114,6 +115,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
114
115
|
tableId?: undefined;
|
|
115
116
|
targetCount?: undefined;
|
|
116
117
|
minPassedCount?: undefined;
|
|
118
|
+
minMessagesCount?: undefined;
|
|
117
119
|
timeoutMs?: undefined;
|
|
118
120
|
intervalMs?: undefined;
|
|
119
121
|
includeRows?: undefined;
|
|
@@ -147,6 +149,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
147
149
|
tableId?: undefined;
|
|
148
150
|
targetCount?: undefined;
|
|
149
151
|
minPassedCount?: undefined;
|
|
152
|
+
minMessagesCount?: undefined;
|
|
150
153
|
timeoutMs?: undefined;
|
|
151
154
|
intervalMs?: undefined;
|
|
152
155
|
includeRows?: undefined;
|
|
@@ -205,6 +208,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
205
208
|
tableId?: undefined;
|
|
206
209
|
targetCount?: undefined;
|
|
207
210
|
minPassedCount?: undefined;
|
|
211
|
+
minMessagesCount?: undefined;
|
|
208
212
|
timeoutMs?: undefined;
|
|
209
213
|
intervalMs?: undefined;
|
|
210
214
|
includeRows?: undefined;
|
|
@@ -263,6 +267,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
263
267
|
tableId?: undefined;
|
|
264
268
|
targetCount?: undefined;
|
|
265
269
|
minPassedCount?: undefined;
|
|
270
|
+
minMessagesCount?: undefined;
|
|
266
271
|
timeoutMs?: undefined;
|
|
267
272
|
intervalMs?: undefined;
|
|
268
273
|
includeRows?: undefined;
|
|
@@ -323,6 +328,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
323
328
|
tableId?: undefined;
|
|
324
329
|
targetCount?: undefined;
|
|
325
330
|
minPassedCount?: undefined;
|
|
331
|
+
minMessagesCount?: undefined;
|
|
326
332
|
timeoutMs?: undefined;
|
|
327
333
|
intervalMs?: undefined;
|
|
328
334
|
includeRows?: undefined;
|
|
@@ -353,6 +359,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
353
359
|
tableId?: undefined;
|
|
354
360
|
targetCount?: undefined;
|
|
355
361
|
minPassedCount?: undefined;
|
|
362
|
+
minMessagesCount?: undefined;
|
|
356
363
|
timeoutMs?: undefined;
|
|
357
364
|
intervalMs?: undefined;
|
|
358
365
|
includeRows?: undefined;
|
|
@@ -383,6 +390,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
383
390
|
tableId?: undefined;
|
|
384
391
|
targetCount?: undefined;
|
|
385
392
|
minPassedCount?: undefined;
|
|
393
|
+
minMessagesCount?: undefined;
|
|
386
394
|
timeoutMs?: undefined;
|
|
387
395
|
intervalMs?: undefined;
|
|
388
396
|
includeRows?: undefined;
|
|
@@ -412,6 +420,10 @@ export declare const rubricToolDefinitions: ({
|
|
|
412
420
|
type: string;
|
|
413
421
|
description: string;
|
|
414
422
|
};
|
|
423
|
+
minMessagesCount: {
|
|
424
|
+
type: string;
|
|
425
|
+
description: string;
|
|
426
|
+
};
|
|
415
427
|
timeoutMs: {
|
|
416
428
|
type: string;
|
|
417
429
|
description: string;
|
|
@@ -508,6 +520,12 @@ export declare function checkRubric(input: CheckRubricInput): Promise<{
|
|
|
508
520
|
export declare function waitForRubricResults(input: WaitForRubricResultsInput): Promise<{
|
|
509
521
|
stats: WorkflowTableStats;
|
|
510
522
|
rows?: import("./rows.js").LightweightRow[] | undefined;
|
|
523
|
+
messageGeneration?: {
|
|
524
|
+
completed: number;
|
|
525
|
+
passingGeneratedMessages: number;
|
|
526
|
+
minMessagesCount: number;
|
|
527
|
+
floorMet: boolean;
|
|
528
|
+
} | undefined;
|
|
511
529
|
ready: boolean;
|
|
512
530
|
attempts: number;
|
|
513
531
|
elapsedMs: number;
|
|
@@ -520,28 +538,14 @@ export declare function waitForRubricResults(input: WaitForRubricResultsInput):
|
|
|
520
538
|
targetCount: number;
|
|
521
539
|
pending?: undefined;
|
|
522
540
|
};
|
|
523
|
-
reason?: undefined;
|
|
524
|
-
partialResult?: undefined;
|
|
525
|
-
diagnostic?: undefined;
|
|
526
|
-
guidance?: undefined;
|
|
527
541
|
} | {
|
|
528
542
|
stats: WorkflowTableStats;
|
|
529
543
|
rows?: import("./rows.js").LightweightRow[] | undefined;
|
|
530
|
-
ready: boolean;
|
|
531
|
-
partial: boolean;
|
|
532
|
-
reason: string;
|
|
533
|
-
attempts: number;
|
|
534
|
-
elapsedMs: number;
|
|
535
|
-
tableId: string;
|
|
536
|
-
passRate: {
|
|
537
|
-
completed: number;
|
|
538
|
-
passed: number;
|
|
539
|
-
pending: number;
|
|
540
|
-
percent: number;
|
|
541
|
-
targetCount: number;
|
|
542
|
-
minPassedCount: number;
|
|
543
|
-
};
|
|
544
544
|
partialResult: {
|
|
545
|
+
messagesCount?: number | undefined;
|
|
546
|
+
passingGeneratedMessages?: number | undefined;
|
|
547
|
+
minMessagesCount?: number | undefined;
|
|
548
|
+
messageFloorMet?: boolean | undefined;
|
|
545
549
|
completed: number;
|
|
546
550
|
passed: number;
|
|
547
551
|
pending: number;
|
|
@@ -551,23 +555,32 @@ export declare function waitForRubricResults(input: WaitForRubricResultsInput):
|
|
|
551
555
|
enoughToDiagnose: boolean;
|
|
552
556
|
floorMet: boolean;
|
|
553
557
|
};
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
558
|
+
messageGeneration?: {
|
|
559
|
+
completed: number;
|
|
560
|
+
passingGeneratedMessages: number;
|
|
561
|
+
minMessagesCount: number;
|
|
562
|
+
floorMet: boolean;
|
|
563
|
+
} | undefined;
|
|
557
564
|
ready: boolean;
|
|
565
|
+
partial: boolean;
|
|
558
566
|
reason: string;
|
|
559
567
|
attempts: number;
|
|
560
568
|
elapsedMs: number;
|
|
561
569
|
tableId: string;
|
|
562
570
|
passRate: {
|
|
563
|
-
minPassedCount?: number | undefined;
|
|
564
571
|
completed: number;
|
|
565
572
|
passed: number;
|
|
566
573
|
pending: number;
|
|
567
574
|
percent: number;
|
|
568
575
|
targetCount: number;
|
|
576
|
+
minPassedCount: number;
|
|
569
577
|
};
|
|
578
|
+
} | {
|
|
570
579
|
partialResult: {
|
|
580
|
+
messagesCount?: number | undefined;
|
|
581
|
+
passingGeneratedMessages?: number | undefined;
|
|
582
|
+
minMessagesCount?: number | undefined;
|
|
583
|
+
messageFloorMet?: boolean | undefined;
|
|
571
584
|
enoughToDiagnose: boolean;
|
|
572
585
|
floorMet: boolean;
|
|
573
586
|
minPassedCount?: number | undefined;
|
|
@@ -581,12 +594,31 @@ export declare function waitForRubricResults(input: WaitForRubricResultsInput):
|
|
|
581
594
|
totalRows: number;
|
|
582
595
|
enrichedCount: number | undefined;
|
|
583
596
|
needsEnrichCount: number | undefined;
|
|
584
|
-
messagesCount: number
|
|
597
|
+
messagesCount: number;
|
|
585
598
|
needsApprovalCount: number | undefined;
|
|
586
599
|
processingCount: number | undefined;
|
|
587
600
|
failedCount: number | undefined;
|
|
588
601
|
};
|
|
589
602
|
guidance: string;
|
|
590
603
|
stats: WorkflowTableStats | null;
|
|
604
|
+
messageGeneration?: {
|
|
605
|
+
completed: number;
|
|
606
|
+
passingGeneratedMessages: number;
|
|
607
|
+
minMessagesCount: number;
|
|
608
|
+
floorMet: boolean;
|
|
609
|
+
} | undefined;
|
|
610
|
+
ready: boolean;
|
|
611
|
+
reason: string;
|
|
612
|
+
attempts: number;
|
|
613
|
+
elapsedMs: number;
|
|
614
|
+
tableId: string;
|
|
615
|
+
passRate: {
|
|
616
|
+
minPassedCount?: number | undefined;
|
|
617
|
+
completed: number;
|
|
618
|
+
passed: number;
|
|
619
|
+
pending: number;
|
|
620
|
+
percent: number;
|
|
621
|
+
targetCount: number;
|
|
622
|
+
};
|
|
591
623
|
}>;
|
|
592
624
|
export {};
|
package/dist/tools/rubrics.js
CHANGED
|
@@ -9,6 +9,11 @@ const DEFAULT_INTERVAL_MS = 2000;
|
|
|
9
9
|
function sleep(ms) {
|
|
10
10
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
11
|
}
|
|
12
|
+
function countPassingGeneratedMessages(rowSnapshot) {
|
|
13
|
+
if (!rowSnapshot?.rows?.length)
|
|
14
|
+
return 0;
|
|
15
|
+
return rowSnapshot.rows.filter((row) => row.icpPassed === true && Boolean(row.message?.trim())).length;
|
|
16
|
+
}
|
|
12
17
|
function normalizeRubricItemDefaults(item) {
|
|
13
18
|
return {
|
|
14
19
|
...item,
|
|
@@ -393,6 +398,10 @@ export const rubricToolDefinitions = [
|
|
|
393
398
|
type: "number",
|
|
394
399
|
description: "Optional pass floor for bounded create-campaign samples. When this floor is met, the tool returns ready:true with partial:true instead of waiting for every target row to finish.",
|
|
395
400
|
},
|
|
401
|
+
minMessagesCount: {
|
|
402
|
+
type: "number",
|
|
403
|
+
description: "Optional generated-message floor. When provided with minPassedCount, the tool waits until both floors are met so create-campaign-v2 can review the first passing generated message without waiting for the full batch.",
|
|
404
|
+
},
|
|
396
405
|
timeoutMs: {
|
|
397
406
|
type: "number",
|
|
398
407
|
description: `Max time to wait in ms (default ${DEFAULT_TIMEOUT_MS}).`,
|
|
@@ -688,6 +697,7 @@ export async function waitForRubricResults(input) {
|
|
|
688
697
|
const intervalMs = Math.max(500, input.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
689
698
|
const targetCount = resolveMaxProspects(input.targetCount);
|
|
690
699
|
const minPassedCount = resolveMinPassedCount(input.minPassedCount);
|
|
700
|
+
const minMessagesCount = resolveMinPassedCount(input.minMessagesCount);
|
|
691
701
|
const includeRows = input.includeRows !== false;
|
|
692
702
|
let tableId = input.tableId;
|
|
693
703
|
if (!tableId && input.campaignOfferId) {
|
|
@@ -709,19 +719,33 @@ export async function waitForRubricResults(input) {
|
|
|
709
719
|
const totalRows = stats.totalRows ?? 0;
|
|
710
720
|
const effectiveTarget = totalRows > 0 ? Math.min(targetCount, totalRows) : targetCount;
|
|
711
721
|
const pending = Math.max(effectiveTarget - completed, 0);
|
|
722
|
+
const messagesCount = stats.messagesCount ?? 0;
|
|
712
723
|
const failedCount = stats.failedCount ?? 0;
|
|
713
724
|
const processingCount = stats.processingCount ?? 0;
|
|
714
725
|
const queuedCount = stats.queuedCount ?? 0;
|
|
715
726
|
const cancellableCount = stats.cancellableCount ?? 0;
|
|
716
727
|
const minPassFloorMet = minPassedCount !== null && passed >= minPassedCount;
|
|
728
|
+
const rawMessageFloorMet = minMessagesCount === null || messagesCount >= minMessagesCount;
|
|
729
|
+
let rowSnapshotForMessageCheck = null;
|
|
730
|
+
let passingGeneratedMessagesCount = null;
|
|
731
|
+
if (minMessagesCount !== null && minPassFloorMet && rawMessageFloorMet) {
|
|
732
|
+
rowSnapshotForMessageCheck = await getTableRowsMinimal(tableId, {
|
|
733
|
+
limit: effectiveTarget,
|
|
734
|
+
});
|
|
735
|
+
passingGeneratedMessagesCount = countPassingGeneratedMessages(rowSnapshotForMessageCheck);
|
|
736
|
+
}
|
|
737
|
+
const messageFloorMet = minMessagesCount === null ||
|
|
738
|
+
(passingGeneratedMessagesCount ?? 0) >= minMessagesCount;
|
|
739
|
+
const earlyFloorMet = minPassFloorMet && messageFloorMet;
|
|
717
740
|
const unresolvedRowsResolvedAsFailures = pending > 0 && completed + failedCount >= effectiveTarget;
|
|
718
741
|
const noActiveProcessing = processingCount === 0 && queuedCount === 0 && cancellableCount === 0;
|
|
719
|
-
if (completed >= effectiveTarget) {
|
|
742
|
+
if (completed >= effectiveTarget && messageFloorMet) {
|
|
720
743
|
const percent = completed > 0 ? Math.round((passed / completed) * 100) : 0;
|
|
721
744
|
const rowSnapshot = includeRows
|
|
722
|
-
?
|
|
723
|
-
|
|
724
|
-
|
|
745
|
+
? (rowSnapshotForMessageCheck ??
|
|
746
|
+
(await getTableRowsMinimal(tableId, {
|
|
747
|
+
limit: effectiveTarget,
|
|
748
|
+
})))
|
|
725
749
|
: null;
|
|
726
750
|
return {
|
|
727
751
|
ready: true,
|
|
@@ -735,11 +759,21 @@ export async function waitForRubricResults(input) {
|
|
|
735
759
|
targetCount: effectiveTarget,
|
|
736
760
|
...(minPassedCount !== null ? { minPassedCount } : {}),
|
|
737
761
|
},
|
|
762
|
+
...(minMessagesCount !== null
|
|
763
|
+
? {
|
|
764
|
+
messageGeneration: {
|
|
765
|
+
completed: messagesCount,
|
|
766
|
+
passingGeneratedMessages: passingGeneratedMessagesCount ?? 0,
|
|
767
|
+
minMessagesCount,
|
|
768
|
+
floorMet: true,
|
|
769
|
+
},
|
|
770
|
+
}
|
|
771
|
+
: {}),
|
|
738
772
|
...(rowSnapshot ? { rows: rowSnapshot.rows } : {}),
|
|
739
773
|
stats,
|
|
740
774
|
};
|
|
741
775
|
}
|
|
742
|
-
if (
|
|
776
|
+
if (earlyFloorMet) {
|
|
743
777
|
const percent = completed > 0 ? Math.round((passed / completed) * 100) : 0;
|
|
744
778
|
const reason = !noActiveProcessing
|
|
745
779
|
? "min_passed_count_met_with_active_processing"
|
|
@@ -747,9 +781,10 @@ export async function waitForRubricResults(input) {
|
|
|
747
781
|
? "min_passed_count_met_with_resolved_failures"
|
|
748
782
|
: "min_passed_count_met_no_active_processing";
|
|
749
783
|
const rowSnapshot = includeRows
|
|
750
|
-
?
|
|
751
|
-
|
|
752
|
-
|
|
784
|
+
? (rowSnapshotForMessageCheck ??
|
|
785
|
+
(await getTableRowsMinimal(tableId, {
|
|
786
|
+
limit: effectiveTarget,
|
|
787
|
+
})))
|
|
753
788
|
: null;
|
|
754
789
|
return {
|
|
755
790
|
ready: true,
|
|
@@ -766,6 +801,16 @@ export async function waitForRubricResults(input) {
|
|
|
766
801
|
targetCount: effectiveTarget,
|
|
767
802
|
minPassedCount,
|
|
768
803
|
},
|
|
804
|
+
...(minMessagesCount !== null
|
|
805
|
+
? {
|
|
806
|
+
messageGeneration: {
|
|
807
|
+
completed: messagesCount,
|
|
808
|
+
passingGeneratedMessages: passingGeneratedMessagesCount ?? 0,
|
|
809
|
+
minMessagesCount,
|
|
810
|
+
floorMet: true,
|
|
811
|
+
},
|
|
812
|
+
}
|
|
813
|
+
: {}),
|
|
769
814
|
partialResult: {
|
|
770
815
|
completed,
|
|
771
816
|
passed,
|
|
@@ -775,6 +820,14 @@ export async function waitForRubricResults(input) {
|
|
|
775
820
|
minPassedCount,
|
|
776
821
|
enoughToDiagnose: true,
|
|
777
822
|
floorMet: true,
|
|
823
|
+
...(minMessagesCount !== null
|
|
824
|
+
? {
|
|
825
|
+
messagesCount,
|
|
826
|
+
passingGeneratedMessages: passingGeneratedMessagesCount ?? 0,
|
|
827
|
+
minMessagesCount,
|
|
828
|
+
messageFloorMet: true,
|
|
829
|
+
}
|
|
830
|
+
: {}),
|
|
778
831
|
},
|
|
779
832
|
...(rowSnapshot ? { rows: rowSnapshot.rows } : {}),
|
|
780
833
|
stats,
|
|
@@ -785,9 +838,21 @@ export async function waitForRubricResults(input) {
|
|
|
785
838
|
const completed = lastStats?.passRate?.completed ?? 0;
|
|
786
839
|
const passed = lastStats?.passRate?.passed ?? 0;
|
|
787
840
|
const percent = completed > 0 ? Math.round((passed / completed) * 100) : 0;
|
|
841
|
+
const messagesCount = lastStats?.messagesCount ?? 0;
|
|
788
842
|
const totalRows = lastStats?.totalRows ?? 0;
|
|
789
843
|
const effectiveTarget = totalRows > 0 ? Math.min(targetCount, totalRows) : targetCount;
|
|
790
844
|
const pending = Math.max(effectiveTarget - completed, 0);
|
|
845
|
+
let timeoutPassingGeneratedMessagesCount = null;
|
|
846
|
+
if (minMessagesCount !== null) {
|
|
847
|
+
try {
|
|
848
|
+
timeoutPassingGeneratedMessagesCount = countPassingGeneratedMessages(await getTableRowsMinimal(tableId, {
|
|
849
|
+
limit: effectiveTarget,
|
|
850
|
+
}));
|
|
851
|
+
}
|
|
852
|
+
catch {
|
|
853
|
+
timeoutPassingGeneratedMessagesCount = null;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
791
856
|
return {
|
|
792
857
|
ready: false,
|
|
793
858
|
reason: "timeout",
|
|
@@ -802,6 +867,16 @@ export async function waitForRubricResults(input) {
|
|
|
802
867
|
targetCount: effectiveTarget,
|
|
803
868
|
...(minPassedCount !== null ? { minPassedCount } : {}),
|
|
804
869
|
},
|
|
870
|
+
...(minMessagesCount !== null
|
|
871
|
+
? {
|
|
872
|
+
messageGeneration: {
|
|
873
|
+
completed: messagesCount,
|
|
874
|
+
passingGeneratedMessages: timeoutPassingGeneratedMessagesCount ?? 0,
|
|
875
|
+
minMessagesCount,
|
|
876
|
+
floorMet: (timeoutPassingGeneratedMessagesCount ?? 0) >= minMessagesCount,
|
|
877
|
+
},
|
|
878
|
+
}
|
|
879
|
+
: {}),
|
|
805
880
|
partialResult: {
|
|
806
881
|
completed,
|
|
807
882
|
passed,
|
|
@@ -811,17 +886,25 @@ export async function waitForRubricResults(input) {
|
|
|
811
886
|
...(minPassedCount !== null ? { minPassedCount } : {}),
|
|
812
887
|
enoughToDiagnose: completed > 0,
|
|
813
888
|
floorMet: minPassedCount !== null && passed >= minPassedCount,
|
|
889
|
+
...(minMessagesCount !== null
|
|
890
|
+
? {
|
|
891
|
+
messagesCount,
|
|
892
|
+
passingGeneratedMessages: timeoutPassingGeneratedMessagesCount ?? 0,
|
|
893
|
+
minMessagesCount,
|
|
894
|
+
messageFloorMet: (timeoutPassingGeneratedMessagesCount ?? 0) >= minMessagesCount,
|
|
895
|
+
}
|
|
896
|
+
: {}),
|
|
814
897
|
},
|
|
815
898
|
diagnostic: {
|
|
816
899
|
totalRows,
|
|
817
900
|
enrichedCount: lastStats?.enrichedCount,
|
|
818
901
|
needsEnrichCount: lastStats?.needsEnrichCount,
|
|
819
|
-
messagesCount
|
|
902
|
+
messagesCount,
|
|
820
903
|
needsApprovalCount: lastStats?.needsApprovalCount,
|
|
821
904
|
processingCount: lastStats?.processingCount,
|
|
822
905
|
failedCount: lastStats?.failedCount,
|
|
823
906
|
},
|
|
824
|
-
guidance: "If this is create-campaign-v2 validate-sample, do not repeat waits indefinitely. Use passRate/stats to diagnose and surface sample_revision_required before Settings when the sample is under the pass floor
|
|
907
|
+
guidance: "If this is create-campaign-v2 validate-sample, do not repeat waits indefinitely. Use passRate/stats to diagnose and surface sample_revision_required before Settings when the sample is under the pass floor. If minMessagesCount is set, one passing generated message is enough to start review; do not wait for a stronger sample.",
|
|
825
908
|
stats: lastStats,
|
|
826
909
|
};
|
|
827
910
|
}
|
package/package.json
CHANGED
|
@@ -49,9 +49,10 @@ for debug output.
|
|
|
49
49
|
12. Sync the approved template into the campaign brief.
|
|
50
50
|
13. After message approval, keep the watched app on Filter Leads while the
|
|
51
51
|
bounded enrichment/filter cascade starts.
|
|
52
|
-
14. Move to Messages only after at least one review row passes
|
|
53
|
-
review
|
|
54
|
-
|
|
52
|
+
14. Move to Messages only after at least one review row passes and one generated
|
|
53
|
+
message is ready for review. Do not wait for a stronger sample once that
|
|
54
|
+
first passing message exists; review it, then hand off to Settings, sender,
|
|
55
|
+
sequence, and explicit launch greenlight.
|
|
55
56
|
|
|
56
57
|
There is no normal approval-packet, commit-gate, atomic-mint, or local
|
|
57
58
|
artifact-validation step. Those belong only to legacy validation/rehearsal
|
|
@@ -1124,8 +1124,14 @@
|
|
|
1124
1124
|
"cellSource": "pending_generate_message_cells_for_passing_rows using approved_campaign_brief_template"
|
|
1125
1125
|
},
|
|
1126
1126
|
{
|
|
1127
|
-
"tool": "
|
|
1128
|
-
"purpose": "
|
|
1127
|
+
"tool": "wait_for_rubric_results",
|
|
1128
|
+
"purpose": "wait_for_first_passing_generated_message",
|
|
1129
|
+
"requiredValues": {
|
|
1130
|
+
"includeRows": false,
|
|
1131
|
+
"minPassedCount": 1,
|
|
1132
|
+
"minMessagesCount": 1
|
|
1133
|
+
},
|
|
1134
|
+
"readVia": "stats_only_tool_result"
|
|
1129
1135
|
},
|
|
1130
1136
|
{
|
|
1131
1137
|
"action": "observe_generate_message_results",
|
|
@@ -1169,25 +1175,24 @@
|
|
|
1169
1175
|
"currentStep": "auto-execute-messaging",
|
|
1170
1176
|
"watchNarration.stage": "review-ready"
|
|
1171
1177
|
},
|
|
1172
|
-
"watchNarrationRule": "Say
|
|
1178
|
+
"watchNarrationRule": "Say the first passing generated message is ready in Messages; next is review before Settings."
|
|
1173
1179
|
},
|
|
1174
1180
|
{
|
|
1175
1181
|
"action": "ask_generated_message_review_choice",
|
|
1176
1182
|
"uses": "request_user_input",
|
|
1177
1183
|
"choices": [
|
|
1178
|
-
"Approve generated
|
|
1184
|
+
"Approve generated message and continue to Settings",
|
|
1179
1185
|
"Revise filters",
|
|
1180
1186
|
"Revise message template",
|
|
1181
1187
|
"Pause here"
|
|
1182
|
-
]
|
|
1183
|
-
"rule": "Do not advance to Settings until the generated review-batch messages have been reviewed and approved."
|
|
1188
|
+
]
|
|
1184
1189
|
}
|
|
1185
1190
|
],
|
|
1186
1191
|
"allowedTools": [
|
|
1187
1192
|
"get_subskill_asset",
|
|
1188
1193
|
"get_rows_minimal",
|
|
1189
1194
|
"queue_cells",
|
|
1190
|
-
"
|
|
1195
|
+
"wait_for_rubric_results",
|
|
1191
1196
|
"update_campaign",
|
|
1192
1197
|
"AskUserQuestion",
|
|
1193
1198
|
"request_user_input"
|
|
@@ -1201,6 +1206,7 @@
|
|
|
1201
1206
|
"hardRules": [
|
|
1202
1207
|
"critique_failure_never_escalates",
|
|
1203
1208
|
"critique_sample_size_bounded_by_config",
|
|
1209
|
+
"first_passing_generated_message_unblocks_review",
|
|
1204
1210
|
"critics_fixed_at_targeting_copy_voice",
|
|
1205
1211
|
"synthesis_enforces_phase_84_token_contract",
|
|
1206
1212
|
"opus_reserved_for_highest_value_subset",
|
|
@@ -60,9 +60,10 @@ auto-revise leads.
|
|
|
60
60
|
explicit batch count anyway so future larger expansion batches do not
|
|
61
61
|
accidentally stop early
|
|
62
62
|
(see §Known Tool Behaviors #3)
|
|
63
|
-
- minPassedCount=1 means one passing filtered row unblocks Step 15
|
|
64
|
-
|
|
65
|
-
before
|
|
63
|
+
- minPassedCount=1 means one passing filtered row unblocks Step 15 Generate
|
|
64
|
+
Message observation. Step 15 then waits only for one generated message
|
|
65
|
+
(`minMessagesCount=1`) before review. Do not wait for all sample rows to
|
|
66
|
+
finish before messages start.
|
|
66
67
|
|
|
67
68
|
7. call `wait_for_rubric_results` with `includeRows=false`; extract ONLY:
|
|
68
69
|
- ready: boolean
|
|
@@ -101,7 +102,9 @@ auto-revise leads.
|
|
|
101
102
|
10. branch:
|
|
102
103
|
if passInSample >= 1:
|
|
103
104
|
proceed to Step 15 (auto-execute-messaging) with currently passing rows
|
|
104
|
-
so Generate Message can start without waiting for the full sample
|
|
105
|
+
so Generate Message can start without waiting for the full sample. Once
|
|
106
|
+
one passing generated message is ready, stop for user review instead of
|
|
107
|
+
waiting for a stronger sample.
|
|
105
108
|
else:
|
|
106
109
|
diagnose (see Brief-vs-List Diagnosis below)
|
|
107
110
|
revisionRound += 1
|
|
@@ -179,7 +182,8 @@ processing makes the experience feel frozen.
|
|
|
179
182
|
|
|
180
183
|
Workaround: treat timeout stats as a partial sample. If at least one row has
|
|
181
184
|
passed, move to Step 15 and observe or queue Generate Message for the passing
|
|
182
|
-
rows
|
|
185
|
+
rows; Step 15 stops when one generated message is ready. If zero rows have
|
|
186
|
+
passed and no active processing is visible, stop at
|
|
183
187
|
`Status: sample-needs-revision` before Settings. Show the completed / passed /
|
|
184
188
|
pending counts and ask whether to revise source, revise filter/rubric, or wait
|
|
185
189
|
once only if active processing is still visible.
|
|
@@ -4,15 +4,16 @@ This reference governs Step 15 (`auto-execute-messaging`) re-cascade
|
|
|
4
4
|
behavior when Step 14's validate-sample loop graduates additional rows
|
|
5
5
|
from pending → passed after the first Generate Message cells have already run.
|
|
6
6
|
|
|
7
|
-
Load whenever Step 15 is about to transition
|
|
8
|
-
`awaiting-user-greenlight`, and on every resume into Step 15.
|
|
7
|
+
Load whenever Step 15 is about to ask for generated-message review or transition
|
|
8
|
+
to `awaiting-user-greenlight`, and on every resume into Step 15.
|
|
9
9
|
|
|
10
10
|
## Principle
|
|
11
11
|
|
|
12
|
-
Generate Message cells are cascade-scoped. If Step 14's rubric flips rows
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
Generate Message cells are cascade-scoped. If Step 14's rubric flips rows from
|
|
13
|
+
pending → passed AFTER Step 15 first observes messages for the review batch, the
|
|
14
|
+
new rows can sit pending with no message. That must not block the first review
|
|
15
|
+
handoff. Step 15 opens review as soon as one passing generated message exists;
|
|
16
|
+
late-passed rows can be re-cascaded after explicit user continuation or resume.
|
|
16
17
|
|
|
17
18
|
Observed on manual Phase-85 signal-discovery run (2026-04-20): 15 new
|
|
18
19
|
rows graduated pending → passed mid-tail while `messagesCount` stayed
|
|
@@ -22,13 +23,17 @@ flat at 257. The new rows never got messages.
|
|
|
22
23
|
|
|
23
24
|
Re-cascade runs whenever ALL of the following are true:
|
|
24
25
|
|
|
25
|
-
1.
|
|
26
|
+
1. The user has already approved the first generated message or explicitly asked
|
|
27
|
+
to continue processing more review-batch rows.
|
|
26
28
|
2. A subsequent check of rubric state shows rows that were pending at
|
|
27
29
|
first message-generation pass are now passed.
|
|
28
30
|
3. Those newly-passed rows do NOT yet have generated messages
|
|
29
31
|
(`messagesCount` flat relative to pre-cascade).
|
|
30
32
|
4. Step 15 has NOT yet transitioned to `awaiting-user-greenlight`.
|
|
31
33
|
|
|
34
|
+
Before that first generated-message approval, do not run this loop just to wait
|
|
35
|
+
for a bigger sample. One passing generated message is enough for review.
|
|
36
|
+
|
|
32
37
|
If condition 4 already fired (i.e. we're in Step 16), the re-cascade
|
|
33
38
|
runs on resume into Step 15 if validate-sample was re-entered and new
|
|
34
39
|
rows graduated.
|
|
@@ -252,16 +252,17 @@ Template approved, bounded filter test running:
|
|
|
252
252
|
"stage": "fit-message",
|
|
253
253
|
"headline": "Template saved",
|
|
254
254
|
"visibleState": "The browser stays on Filter Leads while the bounded enrichment and filter test runs.",
|
|
255
|
-
"agentIntent": "Codex saved the approved message template, queued the review-batch Enrich Prospect cells, and is waiting for
|
|
256
|
-
"nextAction": "
|
|
255
|
+
"agentIntent": "Codex saved the approved message template, queued the review-batch Enrich Prospect cells, and is waiting for one passing row with one generated message before moving to review.",
|
|
256
|
+
"nextAction": "Review the first passing generated message"
|
|
257
257
|
}
|
|
258
258
|
```
|
|
259
259
|
|
|
260
260
|
Do not move to Messages immediately after `approve-message`. The visible route
|
|
261
261
|
is already Filter Leads after `save_rubrics`; approving the message only unlocks
|
|
262
262
|
the bounded cascade from that screen. Move to Messages only once at least one
|
|
263
|
-
review-batch row passes and
|
|
264
|
-
|
|
263
|
+
review-batch row passes and one generated message is ready for review. Do not
|
|
264
|
+
wait for the rest of the review batch or a stronger sample before asking the
|
|
265
|
+
user to approve the generated message.
|
|
265
266
|
|
|
266
267
|
Messages waiting for template:
|
|
267
268
|
|
|
@@ -58,11 +58,12 @@ Step 14 — kick bounded cascade + observe sample
|
|
|
58
58
|
passing filtered row exists.)
|
|
59
59
|
|
|
60
60
|
Step 15 — observe messaging
|
|
61
|
-
|
|
61
|
+
wait_for_rubric_results({ minPassedCount: 1, minMessagesCount: 1, includeRows: false })
|
|
62
|
+
get_rows_minimal # confirm the first passing generated message exists
|
|
62
63
|
(rare) queue_cells on any pending Generate Message cells
|
|
63
64
|
token-contract spot check via get_rows
|
|
64
65
|
update_campaign(currentStep=auto-execute-messaging) with review-ready narration
|
|
65
|
-
ask the user to approve generated
|
|
66
|
+
ask the user to approve the generated message before Settings
|
|
66
67
|
only after approval: update_campaign(currentStep=awaiting-user-greenlight)
|
|
67
68
|
(generate_messages is NOT an MCP tool; messages come from the cascade)
|
|
68
69
|
|
|
@@ -291,8 +292,10 @@ Do not route to a visible `validate-sample` step. Full decision tree lives in
|
|
|
291
292
|
review batch only. After `save_rubrics` and the approved message template are
|
|
292
293
|
persisted, Step 14 queues the review-batch Enrich Prospect cells, waits until
|
|
293
294
|
filter results start landing, then moves to message observation as soon as one
|
|
294
|
-
row passes.
|
|
295
|
-
|
|
295
|
+
row passes. Step 15 opens review as soon as one passing generated message
|
|
296
|
+
exists. Do not wait for a larger or stronger sample once that first passing
|
|
297
|
+
message is ready. It does NOT call `check_rubric`,
|
|
298
|
+
`bulk_enrich_with_prospeo`, or any other direct enrichment/scoring tool.
|
|
296
299
|
|
|
297
300
|
Shape:
|
|
298
301
|
|
|
@@ -307,6 +310,7 @@ projectedPass = round(passInSample / sampleSize * importLimit)
|
|
|
307
310
|
if wait_for_rubric_results.ready === true and passRate.passed >= 1:
|
|
308
311
|
advance to Step 15 to observe or queue Generate Message for currently passing rows
|
|
309
312
|
do not wait for every sample row to finish before message generation starts
|
|
313
|
+
stop for review as soon as one passing generated message is ready
|
|
310
314
|
else if wait_for_rubric_results.ready === false and reason === "timeout":
|
|
311
315
|
use the partial passRate/stats as the sample diagnostic
|
|
312
316
|
if passRate.passed >= 1:
|
|
@@ -382,17 +386,20 @@ Template`. If it does not, fail before the cascade runs. Do not repair
|
|
|
382
386
|
already (cascade auto-fired it). If it is still `pending`, queue
|
|
383
387
|
it explicitly: `queue_cells({ tableId, cellIds:
|
|
384
388
|
<generateMessageCellIds> })`.
|
|
385
|
-
3. `
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
+
3. `wait_for_rubric_results({ tableId, targetCount: reviewBatchSize,
|
|
390
|
+
minPassedCount: 1, minMessagesCount: 1, includeRows: false })` until the
|
|
391
|
+
first passing generated message is ready. Do not wait for every passing row's
|
|
392
|
+
Generate Message cell, and do not add "one more wait" for a stronger sample.
|
|
393
|
+
Remaining review-batch rows can continue processing in the background.
|
|
394
|
+
4. Read the first ready generated message back via `get_rows` (full) and
|
|
395
|
+
sanity-check that sample against the Phase 84 token contract: no unresolved
|
|
389
396
|
`{{tokens}}`, no invented proof, one sentence per line, etc.
|
|
390
397
|
5. If the sample fails the token contract, diagnose brief-vs-list
|
|
391
398
|
(same revision loop as Step 14) and escalate if over
|
|
392
399
|
`maxRevisionRounds`.
|
|
393
|
-
6. On success, keep `currentStep: "auto-execute-messaging"` and ask the user
|
|
394
|
-
|
|
395
|
-
the campaign to Settings / `awaiting-user-greenlight`.
|
|
400
|
+
6. On success, keep `currentStep: "auto-execute-messaging"` and ask the user to
|
|
401
|
+
approve the generated message before continuing to Settings. Only that
|
|
402
|
+
approval may move the campaign to Settings / `awaiting-user-greenlight`.
|
|
396
403
|
|
|
397
404
|
**Do NOT hand-write message bodies via `update_cell`.** `update_cell`
|
|
398
405
|
is reachable for legitimate operator overrides AFTER the tail hands
|
|
@@ -432,15 +439,16 @@ strings, which is why Step 16 requires Step 15 to be complete.
|
|
|
432
439
|
4. Check `messaging.tokenContract`. When `strict`, reject any sample
|
|
433
440
|
message that contains unresolved or unsupported tokens (including
|
|
434
441
|
any critique rewrite that tried to introduce one).
|
|
435
|
-
5. If the
|
|
436
|
-
stop at the review-batch handoff. Do NOT
|
|
437
|
-
|
|
442
|
+
5. If the first passing generated message passes the token contract (and
|
|
443
|
+
critique when enabled), stop at the review-batch handoff. Do NOT wait for the
|
|
444
|
+
remaining review-batch rows and do NOT scale to the full source list before
|
|
445
|
+
explicit user expansion approval.
|
|
438
446
|
6. If the sample fails the token contract or critique, diagnose +
|
|
439
447
|
loop the same way Step 14 does (brief-vs-list), subject to the same
|
|
440
448
|
`maxRevisionRounds` cap.
|
|
441
449
|
7. On success, keep `currentStep: "auto-execute-messaging"`, show that the
|
|
442
|
-
|
|
443
|
-
Settings. Only after the user approves
|
|
450
|
+
first passing generated message is ready in Messages, and ask for approval
|
|
451
|
+
before Settings. Only after the user approves the generated message should
|
|
444
452
|
`update_campaign({ campaignId, currentStep: "awaiting-user-greenlight" })`
|
|
445
453
|
run.
|
|
446
454
|
|