backend-manager 5.9.16 → 5.9.18

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.
@@ -2,7 +2,7 @@ WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
2
2
  WARNING: sun.misc.Unsafe::allocateMemory has been called by io.netty.util.internal.PlatformDependent0$2 (file:/Users/ian/.cache/firebase/emulators/cloud-firestore-emulator-v1.21.0.jar)
3
3
  WARNING: Please consider reporting this to the maintainers of class io.netty.util.internal.PlatformDependent0$2
4
4
  WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
5
- Jun 25, 2026 9:48:48 PM com.google.cloud.datastore.emulator.firestore.websocket.WebSocketServer start
5
+ Jun 26, 2026 5:05:47 PM com.google.cloud.datastore.emulator.firestore.websocket.WebSocketServer start
6
6
  INFO: Started WebSocket server on ws://127.0.0.1:9150
7
7
 
8
8
  API endpoint: http://127.0.0.1:8080
@@ -20,115 +20,115 @@ If you are running a Firestore in Datastore Mode project, run:
20
20
  Note: Support for Datastore Mode is in preview. If you encounter any bugs please file at https://github.com/firebase/firebase-tools/issues.
21
21
  Dev App Server is now running.
22
22
 
23
- Jun 25, 2026 9:48:58 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
23
+ Jun 26, 2026 5:05:57 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
24
24
  INFO: Detected non-HTTP/2 connection.
25
- Jun 25, 2026 9:48:59 PM io.grpc.netty.TcpMetrics loadEpollInfo
25
+ Jun 26, 2026 5:05:57 PM io.grpc.netty.TcpMetrics loadEpollInfo
26
26
  INFO: Epoll available during static init of TcpMetrics:false
27
- Jun 25, 2026 9:48:59 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
27
+ Jun 26, 2026 5:05:57 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
28
28
  INFO: Detected HTTP/2 connection.
29
- Jun 25, 2026 9:49:00 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
29
+ Jun 26, 2026 5:05:59 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
30
30
  INFO: Detected HTTP/2 connection.
31
- Jun 25, 2026 9:49:00 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
31
+ Jun 26, 2026 5:05:59 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
32
32
  INFO: Detected HTTP/2 connection.
33
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
33
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
34
34
  INFO: Detected HTTP/2 connection.
35
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
35
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
36
36
  INFO: Detected HTTP/2 connection.
37
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
37
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
38
38
  INFO: Detected HTTP/2 connection.
39
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
39
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
40
40
  INFO: Detected HTTP/2 connection.
41
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
41
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
42
42
  INFO: Detected HTTP/2 connection.
43
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
43
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
44
44
  INFO: Detected HTTP/2 connection.
45
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
45
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
46
46
  INFO: Detected HTTP/2 connection.
47
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
47
+ Jun 26, 2026 5:06:08 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
48
48
  INFO: Detected HTTP/2 connection.
49
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
49
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
50
50
  INFO: Detected HTTP/2 connection.
51
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
51
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
52
52
  INFO: Detected HTTP/2 connection.
53
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
53
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
54
54
  INFO: Detected HTTP/2 connection.
55
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
55
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
56
56
  INFO: Detected HTTP/2 connection.
57
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
57
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
58
58
  INFO: Detected HTTP/2 connection.
59
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
59
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
60
60
  INFO: Detected HTTP/2 connection.
61
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
61
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
62
62
  INFO: Detected HTTP/2 connection.
63
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
63
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
64
64
  INFO: Detected HTTP/2 connection.
65
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
65
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
66
66
  INFO: Detected HTTP/2 connection.
67
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
67
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
68
68
  INFO: Detected HTTP/2 connection.
69
- Jun 25, 2026 9:49:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
69
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
70
70
  INFO: Detected HTTP/2 connection.
71
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
71
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
72
72
  INFO: Detected HTTP/2 connection.
73
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
73
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
74
74
  INFO: Detected HTTP/2 connection.
75
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
75
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
76
76
  INFO: Detected HTTP/2 connection.
77
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
77
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
78
78
  INFO: Detected HTTP/2 connection.
79
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
79
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
80
80
  INFO: Detected HTTP/2 connection.
81
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
81
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
82
82
  INFO: Detected HTTP/2 connection.
83
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
83
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
84
84
  INFO: Detected HTTP/2 connection.
85
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
85
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
86
86
  INFO: Detected HTTP/2 connection.
87
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
87
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
88
88
  INFO: Detected HTTP/2 connection.
89
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
89
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
90
90
  INFO: Detected HTTP/2 connection.
91
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
91
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
92
92
  INFO: Detected HTTP/2 connection.
93
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
93
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
94
94
  INFO: Detected HTTP/2 connection.
95
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
95
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
96
96
  INFO: Detected HTTP/2 connection.
97
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
97
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
98
98
  INFO: Detected HTTP/2 connection.
99
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
99
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
100
100
  INFO: Detected HTTP/2 connection.
101
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
101
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
102
102
  INFO: Detected HTTP/2 connection.
103
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
103
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
104
104
  INFO: Detected HTTP/2 connection.
105
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
105
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
106
106
  INFO: Detected HTTP/2 connection.
107
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
107
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
108
108
  INFO: Detected HTTP/2 connection.
109
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
109
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
110
110
  INFO: Detected HTTP/2 connection.
111
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
111
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
112
112
  INFO: Detected HTTP/2 connection.
113
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
113
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
114
114
  INFO: Detected HTTP/2 connection.
115
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
115
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
116
116
  INFO: Detected HTTP/2 connection.
117
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
117
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
118
118
  INFO: Detected HTTP/2 connection.
119
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
119
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
120
120
  INFO: Detected HTTP/2 connection.
121
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
121
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
122
122
  INFO: Detected HTTP/2 connection.
123
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
123
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
124
124
  INFO: Detected HTTP/2 connection.
125
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
125
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
126
126
  INFO: Detected HTTP/2 connection.
127
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
127
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
128
128
  INFO: Detected HTTP/2 connection.
129
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
129
+ Jun 26, 2026 5:06:09 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
130
130
  INFO: Detected HTTP/2 connection.
131
- Jun 25, 2026 9:49:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
131
+ Jun 26, 2026 5:06:10 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
132
132
  INFO: Detected HTTP/2 connection.
133
133
  *** shutting down gRPC server since JVM is shutting down
134
134
  *** server shut down
@@ -1,6 +1,6 @@
1
1
  This is the Google Pub/Sub fake.
2
2
  Implementation may be incomplete or differ from the real system.
3
- Jun 25, 2026 9:48:52 PM com.google.cloud.pubsub.testing.v1.Main main
3
+ Jun 26, 2026 5:05:51 PM com.google.cloud.pubsub.testing.v1.Main main
4
4
  INFO: IAM integration is disabled. IAM policy methods and ACL checks are not supported
5
5
  SLF4J(W): No SLF4J providers were found.
6
6
  SLF4J(W): Defaulting to no-operation (NOP) logger implementation
@@ -9,9 +9,9 @@ WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
9
9
  WARNING: sun.misc.Unsafe::allocateMemory has been called by io.netty.util.internal.PlatformDependent0$2 (file:/Users/ian/.cache/firebase/emulators/pubsub-emulator-0.8.33/pubsub-emulator/lib/cloud-pubsub-emulator-0.8.33-all.jar)
10
10
  WARNING: Please consider reporting this to the maintainers of class io.netty.util.internal.PlatformDependent0$2
11
11
  WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
12
- Jun 25, 2026 9:48:53 PM com.google.cloud.pubsub.testing.v1.Main main
12
+ Jun 26, 2026 5:05:52 PM com.google.cloud.pubsub.testing.v1.Main main
13
13
  INFO: Server started, listening on 8085
14
- Jun 25, 2026 9:48:59 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
14
+ Jun 26, 2026 5:05:58 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
15
15
  INFO: Detected HTTP/2 connection.
16
16
  *** shutting down gRPC server since JVM is shutting down
17
17
  *** server shut down
@@ -41,6 +41,11 @@
41
41
  * NEWSLETTER_OPEN=1 Auto-open the rendered preview in the default browser (macOS only).
42
42
  *
43
43
  * --- AI-mode-only env vars (require TEST_EXTENDED_MODE=1) ---
44
+ * NEWSLETTER_SOURCE=<type> Override the source type for this run. Bypasses parent-server
45
+ * fetch and lets the generator's built-in resolver run.
46
+ * Values: '$feed:<url>', '$parent'. When set, sources[] in the
47
+ * config is replaced with this single source.
48
+ * Example: NEWSLETTER_SOURCE='$feed:https://feeds.arstechnica.com/arstechnica/index'
44
49
  * NEWSLETTER_PEEK=1 Fetch + list ready sources, do not claim, exit.
45
50
  * NEWSLETTER_SOURCE_ID=<id> Generate from one specific source WITHOUT claiming it.
46
51
  * NEWSLETTER_LIMIT=10 Sources per category for PEEK (default 10).
@@ -325,60 +330,57 @@ module.exports = {
325
330
  // `api.` subdomain (e.g. 'https://itwcreativeworks.com'); the helper
326
331
  // inserts `api.` at call time. PARENT_API_URL env override is honored
327
332
  // verbatim for one-off testing against a different parent.
328
- const parentUrl = env.PARENT_API_URL || Manager.getParentApiUrl();
329
- assert.ok(parentUrl, 'PARENT_API_URL (env) or parent (config) must be set for the AI pipeline. Set TEST_EXTENDED_MODE=1 to run it, or omit TEST_EXTENDED_MODE for the fast fixture preview.');
333
+ // When NEWSLETTER_SOURCE is set, skip parent URL checks and source fetching —
334
+ // the generator's built-in resolver (resolveNewsletterSources) handles everything.
335
+ let sources = [];
336
+
337
+ if (!env.NEWSLETTER_SOURCE) {
338
+ const parentUrl = env.PARENT_API_URL || Manager.getParentApiUrl();
339
+ assert.ok(parentUrl, 'PARENT_API_URL (env) or parent (config) must be set for the AI pipeline. Set TEST_EXTENDED_MODE=1 to run it, or omit TEST_EXTENDED_MODE for the fast fixture preview.');
340
+
341
+ // --- Peek mode (early return) ---
342
+ if (env.NEWSLETTER_PEEK) {
343
+ const peeked = await peekSources({
344
+ parentUrl,
345
+ categories: newsletterConfig.categories || [],
346
+ limit: parseInt(env.NEWSLETTER_LIMIT, 10) || 10,
347
+ key: env.BACKEND_MANAGER_KEY,
348
+ });
349
+
350
+ console.log(`\nPeek mode — ${peeked.length} ready source(s):\n`);
351
+ peeked.forEach((s, i) => {
352
+ const raw = s.source || {};
353
+ const cats = (s.categories || []).join(', ') || s.category || '(none)';
354
+ console.log(`[${i + 1}] ${s.id}`);
355
+ console.log(` Categories: ${cats}`);
356
+ console.log(` From: ${raw.from || s.from || '(unknown)'}`);
357
+ console.log(` Subject: ${raw.subject || s.subject || '(none)'}`);
358
+ console.log(` Headline: ${s.ai?.headline || '(none — not yet AI-processed)'}`);
359
+ console.log('');
360
+ });
361
+
362
+ assert.ok(true, `Peeked ${peeked.length} sources`);
363
+ return;
364
+ }
330
365
 
331
- // --- Peek mode (early return) ---
332
- if (env.NEWSLETTER_PEEK) {
333
- const sources = await peekSources({
366
+ // --- Fetch sources ---
367
+ const claim = !!env.NEWSLETTER_CLAIM;
368
+ sources = await fetchSourcesForRun({
334
369
  parentUrl,
335
- categories: newsletterConfig.categories || [],
336
- limit: parseInt(env.NEWSLETTER_LIMIT, 10) || 10,
370
+ newsletterConfig,
371
+ brandId: config.brand?.id,
372
+ sourceId: env.NEWSLETTER_SOURCE_ID,
337
373
  key: env.BACKEND_MANAGER_KEY,
374
+ claim,
338
375
  });
339
376
 
340
- console.log(`\nPeek mode — ${sources.length} ready source(s):\n`);
341
- sources.forEach((s, i) => {
342
- const raw = s.source || {};
343
- const cats = (s.categories || []).join(', ') || s.category || '(none)';
344
- console.log(`[${i + 1}] ${s.id}`);
345
- console.log(` Categories: ${cats}`);
346
- console.log(` From: ${raw.from || s.from || '(unknown)'}`);
347
- console.log(` Subject: ${raw.subject || s.subject || '(none)'}`);
348
- console.log(` Headline: ${s.ai?.headline || '(none — not yet AI-processed)'}`);
349
- console.log('');
350
- });
351
-
352
- assert.ok(true, `Peeked ${sources.length} sources`);
353
- return;
354
- }
355
-
356
- // --- Fetch sources ---
357
- // By DEFAULT the test does NOT claim sources — it fetches them without
358
- // claimFor, so they stay 'ready' and available for the real newsletter.
359
- // This keeps test runs repeatable and non-destructive (a test should never
360
- // silently consume production resources). Set NEWSLETTER_CLAIM=1 to exercise
361
- // the real claim/consume path (then use NEWSLETTER_RELEASE=1 to put them back).
362
- const claim = !!env.NEWSLETTER_CLAIM;
363
- const sources = await fetchSourcesForRun({
364
- parentUrl,
365
- newsletterConfig,
366
- brandId: config.brand?.id,
367
- sourceId: env.NEWSLETTER_SOURCE_ID,
368
- key: env.BACKEND_MANAGER_KEY,
369
- claim,
370
- });
371
-
372
- // Environmental precondition: the parent server must have ready sources in
373
- // at least one configured category. Skip cleanly when the pool is empty
374
- // (transient state — no point hard-failing CI on an external queue).
375
- if (sources.length === 0) {
376
- return skip('No ready newsletter sources available on parent server (environmental)');
377
- }
377
+ if (sources.length === 0) {
378
+ return skip('No ready newsletter sources available on parent server (environmental)');
379
+ }
378
380
 
379
- // Track claimed IDs for later --release-all (only when we actually claimed)
380
- if (claim && !env.NEWSLETTER_SOURCE_ID) {
381
- appendClaimed(claimedFile, sources.map((s) => s.id));
381
+ if (claim && !env.NEWSLETTER_SOURCE_ID) {
382
+ appendClaimed(claimedFile, sources.map((s) => s.id));
383
+ }
382
384
  }
383
385
 
384
386
  // Force `newsletter.enabled: true` and inject the per-run newsletter config
@@ -432,12 +434,25 @@ module.exports = {
432
434
 
433
435
  console.log(`[extended] uploading to itw-creative-works/newsletter-assets/${config.brand?.id}/${campaignId || '<auto-id>'}/ + Beehiiv draft`);
434
436
 
437
+ // NEWSLETTER_SOURCE overrides the configured sources[] and lets the
438
+ // generator's built-in resolver run (resolveNewsletterSources). Without
439
+ // this, the test always passes pre-fetched parent sources via opts.sources,
440
+ // bypassing feed resolution entirely.
441
+ // NEWSLETTER_SOURCE='$feed:https://feeds.arstechnica.com/arstechnica/index'
442
+ // NEWSLETTER_SOURCE='$parent' (default behavior, explicit)
443
+ const useResolverSources = !!env.NEWSLETTER_SOURCE;
444
+
445
+ if (useResolverSources) {
446
+ newsletterConfig.sources = [env.NEWSLETTER_SOURCE];
447
+ Manager.config.marketing.newsletter.content = newsletterConfig;
448
+ }
449
+
435
450
  const result = await generator.generate(
436
451
  Manager,
437
452
  assistant,
438
- { name: `Somiibo Newsletter — Iteration ${stamp}` },
453
+ { name: `${config.brand?.name || 'Brand'} Newsletter — Iteration ${stamp}` },
439
454
  {
440
- sources,
455
+ sources: useResolverSources ? undefined : sources,
441
456
  skipClaim: true, // We manage the claim/release lifecycle ourselves
442
457
  skipImages: !!env.NEWSLETTER_NO_IMAGES,
443
458
  // The article is GENERATED whenever the brand's config.article.enabled is on