@bongos/core 1.19.1065 → 1.19.1067
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/.bongos-core.json +40 -30
- package/docs/adr/0341-the-page-is-the-unit-of-tweak-mode.md +3 -0
- package/docs/branding-contract.md +1 -1
- package/docs/copy-inventory.md +24 -24
- package/docs/copy-registry.json +28 -28
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-readings.json +12 -12
- package/modules/copy-desk/page-status.js +4 -2
- package/modules/copy-desk/routes/copy-desk.js +3 -2
- package/modules/economy/credits.js +77 -0
- package/modules/economy/reward-policy.js +7 -1
- package/modules/economy/reward.js +4 -0
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/studio.js +12 -9
- package/modules/lifecycle/cascade.js +48 -96
- package/modules/lifecycle/db-ship.js +14 -5
- package/modules/lifecycle/routes/lifecycle.js +9 -9
- package/modules/lifecycle/tests/cascade.mjs +106 -160
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/src/module-api.js +1 -1
- package/tests/artist_page_credit.mjs +272 -0
- package/tests/grader_reader_lens.mjs +16 -24
- package/tests/removal_verdict.mjs +5 -2
- package/tests/tweak_replaces_artist_review.mjs +170 -0
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
// 3. it says where it came from
|
|
12
12
|
// 4. it files at backlog, never ready
|
|
13
13
|
//
|
|
14
|
-
// The
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
14
|
+
// The mechanism is proved by the test's OWN declarations, not a production
|
|
15
|
+
// rule — which is also the point: a mechanism proved against the contract
|
|
16
|
+
// rather than one example survives its rules coming and going (the artist
|
|
17
|
+
// review, R04's, was removed by TW14).
|
|
18
18
|
//
|
|
19
19
|
// DB-free: the runner takes its three database calls as injected functions.
|
|
20
20
|
|
|
@@ -185,7 +185,13 @@ await test('the production table is valid, and a duplicate key is refused', () =
|
|
|
185
185
|
assert.ok(shape.some((p) => /body/.test(p)));
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
// --- the
|
|
188
|
+
// --- the artist review is GONE: Tweak Mode replaced it (TW14, ADR 0341 D9) ----
|
|
189
|
+
//
|
|
190
|
+
// R04 (task 1003115) wrote `artist-review-on-ship`, which filed an artist review
|
|
191
|
+
// for every copy/visual ship. Task 1004325 removed it: a ship that changes a
|
|
192
|
+
// page's words writes NOTHING, and the page reads "changed since last tweak"
|
|
193
|
+
// because drift is derived (D8). tests/tweak_replaces_artist_review.mjs proves
|
|
194
|
+
// that second half on the whole path; these pin the first.
|
|
189
195
|
|
|
190
196
|
const shippedCopy = (over = {}) => ({
|
|
191
197
|
id: '7001', version_id: 'BONGOS-V1', goal_id: '1000074',
|
|
@@ -194,66 +200,59 @@ const shippedCopy = (over = {}) => ({
|
|
|
194
200
|
...over,
|
|
195
201
|
});
|
|
196
202
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
203
|
+
// A test rule that records the ctx the runner handed it, so the runner's
|
|
204
|
+
// resolution of policy and changed files is still pinned with no production
|
|
205
|
+
// rule reading either.
|
|
206
|
+
const ctxProbe = () => {
|
|
207
|
+
const seen = [];
|
|
208
|
+
return {
|
|
209
|
+
seen,
|
|
210
|
+
rule: {
|
|
211
|
+
key: 'test-ctx-probe',
|
|
212
|
+
discipline: 'artist',
|
|
213
|
+
when: (t, ctx) => { seen.push(ctx); return false; },
|
|
214
|
+
title: () => 'never',
|
|
215
|
+
body: () => 'never',
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
await test('the artist review rule is gone from CASCADES, and the table stays well-formed', () => {
|
|
221
|
+
assert.equal(cascade.CASCADES.find((x) => x.key === 'artist-review-on-ship'), undefined,
|
|
222
|
+
'Tweak Mode replaced the per-ship review (ADR 0341 D9)');
|
|
223
|
+
assert.equal(cascade.artistReviewBody, undefined, 'its body went with it');
|
|
224
|
+
assert.deepEqual(cascade.validateCascades(), [], 'the shipped table is well-formed');
|
|
211
225
|
});
|
|
212
226
|
|
|
213
227
|
await test('the production rule set is exactly what is declared', () => {
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
// and silently suppress one another, which validateCascades
|
|
217
|
-
assert.deepEqual(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
228
|
+
// Adding a rule is a deliberate act, so it should have to be recorded here,
|
|
229
|
+
// and a rule vanishing fails here too. Duplicate keys would collide on
|
|
230
|
+
// source_ref and silently suppress one another, which validateCascades refuses.
|
|
231
|
+
assert.deepEqual(cascade.CASCADES.map((r) => r.key).sort(), ['removal-proposed-on-ship']);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await test('a copy/visual ship files NO artist review, at every artist-gate level', () => {
|
|
235
|
+
for (const ctx of [undefined, {}, { artistGate: 'strict' }, { artistGate: 'advisory' }, { artistGate: 'off' }, { artistGate: undefined }]) {
|
|
236
|
+
const { matched, errors } = cascade.cascadesFor(shippedCopy(), cascade.CASCADES, ctx);
|
|
237
|
+
assert.deepEqual(errors, []);
|
|
238
|
+
assert.equal(matched.length, 0, `nothing filed with ctx ${JSON.stringify(ctx)}`);
|
|
239
|
+
}
|
|
240
|
+
// Every shape that USED to file one: a copy proposal landing, an artist's own
|
|
241
|
+
// work, an unlabelled ship that changed a page file, and a truncated file list.
|
|
242
|
+
const shapes = [
|
|
243
|
+
[shippedCopy({ module_key: null, source: 'copy-proposal' }), {}],
|
|
244
|
+
[shippedCopy({ module_key: null, discipline: 'artist' }), {}],
|
|
245
|
+
[shippedCopy({ module_key: null }), { changedFiles: ['modules/hall-ui/public/studio.html'] }],
|
|
246
|
+
[shippedCopy({ module_key: null }), { changedFiles: [], changedFilesTruncated: true }],
|
|
247
|
+
];
|
|
248
|
+
for (const [task, ctx] of shapes) {
|
|
249
|
+
assert.equal(cascade.cascadesFor(task, cascade.CASCADES, ctx).matched.length, 0, JSON.stringify(ctx));
|
|
250
|
+
}
|
|
221
251
|
});
|
|
222
252
|
|
|
223
|
-
await test('
|
|
224
|
-
|
|
225
|
-
assert.equal(
|
|
226
|
-
const spec = matched[0].spec;
|
|
227
|
-
assert.equal(spec.discipline, 'artist');
|
|
228
|
-
assert.equal(spec.kind, 'unclassified');
|
|
229
|
-
assert.equal(spec.status, 'backlog', 'a request that triage may dismiss — not claimable, not nagging');
|
|
230
|
-
assert.match(spec.title, /7001/);
|
|
231
|
-
// Both steps, and both routes of step 2, are in the body.
|
|
232
|
-
//
|
|
233
|
-
// STEP 1's label tracks ADR 0298 (task 1003937), and it has now turned twice.
|
|
234
|
-
// It first read "REVIEW THE GRADER … coach it", which asked for something no
|
|
235
|
-
// artist could do: the panel's four lenses read completion, code quality,
|
|
236
|
-
// security and runtime cost, so there was no copy verdict to coach. It was
|
|
237
|
-
// rewritten to ask for the RECORD instead, as an explicitly INTERIM wording,
|
|
238
|
-
// pinned here so a well-meaning copy-edit could not restore the unfollowable
|
|
239
|
-
// version without reading why.
|
|
240
|
-
//
|
|
241
|
-
// Task 1003977 shipped the advisory reader lens and the voice guide it waited
|
|
242
|
-
// on (task 1003976), so the step is coaching again — and this pin moves with
|
|
243
|
-
// it. The two must turn TOGETHER: the wording is the signal for which world
|
|
244
|
-
// we are in, so a body that still said "no lens reads a sentence" after the
|
|
245
|
-
// lens landed would send every artist looking for a counterpart that is
|
|
246
|
-
// sitting right there in the grade record.
|
|
247
|
-
assert.match(spec.description, /STEP 1 — COACH THE READER/);
|
|
248
|
-
assert.match(spec.description, /docs\/voice\.md/, 'and names the written standard to coach against');
|
|
249
|
-
assert.doesNotMatch(spec.description, /none of them reads a sentence/,
|
|
250
|
-
'the interim claim is gone — it stopped being true when the reader shipped');
|
|
251
|
-
assert.match(spec.description, /ADR 0298/, 'the step names the decision that shaped it');
|
|
252
|
-
assert.match(spec.description, /STEP 2 — REMAKE OR TWEAK/);
|
|
253
|
-
assert.match(spec.description, /OUTSIDE the AI chat/);
|
|
254
|
-
assert.match(spec.description, /WITH it/);
|
|
255
|
-
assert.match(spec.description, /DISMISS this in triage/);
|
|
256
|
-
assert.match(spec.description, /blocks nothing that shipped/, 'it says out loud that it is not a gate');
|
|
253
|
+
await test('hasCopyOrVisualWork STAYS, because the grader\'s reader lens is scoped by it', () => {
|
|
254
|
+
assert.equal(typeof cascade.hasCopyOrVisualWork, 'function');
|
|
255
|
+
assert.equal(cascade.hasCopyOrVisualWork(shippedCopy()), true, 'a hall-ui ship is still copy/visual work');
|
|
257
256
|
});
|
|
258
257
|
|
|
259
258
|
await test('"copy or visuals" is a NARROW predicate — three ways in, and a default of no', () => {
|
|
@@ -262,49 +261,33 @@ await test('"copy or visuals" is a NARROW predicate — three ways in, and a def
|
|
|
262
261
|
assert.equal(H(shippedCopy({ module_key: 'art-pipeline' })), true);
|
|
263
262
|
assert.equal(H(shippedCopy({ module_key: null, source: 'copy-proposal' })), true, 'a landed copy proposal');
|
|
264
263
|
assert.equal(H(shippedCopy({ module_key: null, source: 'manual', discipline: 'artist' })), true, 'work an artist did');
|
|
265
|
-
// The default is NO — a backend/infra ship is not
|
|
264
|
+
// The default is NO — a backend/infra ship is not copy/visual work.
|
|
266
265
|
assert.equal(H(shippedCopy({ module_key: 'lifecycle', discipline: 'engineer', source: 'manual' })), false);
|
|
267
266
|
assert.equal(H(shippedCopy({ module_key: null, discipline: 'engineer', source: 'manual' })), false);
|
|
268
267
|
assert.equal(H(null), false);
|
|
269
268
|
});
|
|
270
269
|
|
|
271
|
-
await test('THE ANTI-RECURSION GUARD:
|
|
272
|
-
// The
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
270
|
+
await test('THE ANTI-RECURSION GUARD: a cascade-generated task shipping matches no production rule', () => {
|
|
271
|
+
// The removal rule's guard: even a cascade task whose ship deleted earlier
|
|
272
|
+
// work files nothing, so generation stays a single hop.
|
|
273
|
+
const cascaded = shippedCopy({ discipline: 'artist', source: cascade.CASCADE_SOURCE, module_key: null, id: '7100' });
|
|
274
|
+
const { matched } = cascade.cascadesFor(cascaded, cascade.CASCADES, {
|
|
275
|
+
removals: [{ taskId: '42', paths: ['a.js'] }],
|
|
277
276
|
});
|
|
278
|
-
|
|
279
|
-
assert.equal(matched.length, 0, 'a cascade-generated task never triggers another cascade');
|
|
277
|
+
assert.equal(matched.length, 0);
|
|
280
278
|
});
|
|
281
279
|
|
|
282
|
-
|
|
283
|
-
// A copy ship in some other goal gets its review filed next to that work.
|
|
284
|
-
const { matched } = cascade.cascadesFor(shippedCopy({ goal_id: '1000046', version_id: 'BONGOS-V1' }));
|
|
285
|
-
assert.equal(matched[0].spec.goalId, 1000046);
|
|
286
|
-
assert.equal(matched[0].spec.versionId, 'BONGOS-V1');
|
|
287
|
-
});
|
|
280
|
+
// --- the runner still resolves its policy and the changed files --------------
|
|
288
281
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
await
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
assert.equal(
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
await test('an UNREAD policy files — silence is never read as an opt-out', () => {
|
|
300
|
-
// No context at all (an old caller), and an explicitly-undefined level (a reader
|
|
301
|
-
// that threw) must both behave like the gate's default, which is 'strict'.
|
|
302
|
-
assert.equal(cascade.cascadesFor(shippedCopy()).matched.length, 1);
|
|
303
|
-
assert.equal(cascade.cascadesFor(shippedCopy(), cascade.CASCADES, {}).matched.length, 1);
|
|
304
|
-
assert.equal(cascade.cascadesFor(shippedCopy(), cascade.CASCADES, { artistGate: undefined }).matched.length, 1);
|
|
305
|
-
});
|
|
282
|
+
await test('the runner still hands the artist gate to the rules, and a reader that THROWS is reported', async () => {
|
|
283
|
+
const ok = ctxProbe();
|
|
284
|
+
await cascade.runCascadesForShip({ id: '7001' }, {
|
|
285
|
+
rules: [ok.rule], getTask: async () => shippedCopy(),
|
|
286
|
+
findTaskBySourceRef: async () => null, createTask: async () => ({ id: '1' }),
|
|
287
|
+
artistGateMode: () => 'advisory',
|
|
288
|
+
});
|
|
289
|
+
assert.equal(ok.seen[0].artistGate, 'advisory');
|
|
306
290
|
|
|
307
|
-
await test('a gate reader that THROWS costs the run nothing — it is reported, and the review is still filed', async () => {
|
|
308
291
|
const created = [];
|
|
309
292
|
const report = await cascade.runCascadesForShip({ id: '7001' }, {
|
|
310
293
|
getTask: async () => shippedCopy(),
|
|
@@ -312,24 +295,11 @@ await test('a gate reader that THROWS costs the run nothing — it is reported,
|
|
|
312
295
|
createTask: async (spec) => { created.push(spec); return { id: '7002' }; },
|
|
313
296
|
artistGateMode: () => { throw new Error('pack unreadable'); },
|
|
314
297
|
});
|
|
315
|
-
assert.equal(created.length,
|
|
316
|
-
assert.ok(report.errors.some((e) => /artistGateMode\(\) threw/.test(e)), '
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
await test("runCascadesForShip honours 'off' end to end — nothing is created, nothing errors", async () => {
|
|
320
|
-
let creates = 0;
|
|
321
|
-
const report = await cascade.runCascadesForShip({ id: '7001' }, {
|
|
322
|
-
getTask: async () => shippedCopy(),
|
|
323
|
-
findTaskBySourceRef: async () => null,
|
|
324
|
-
createTask: async () => { creates++; return { id: '7002' }; },
|
|
325
|
-
artistGateMode: () => 'off',
|
|
326
|
-
});
|
|
327
|
-
assert.equal(creates, 0);
|
|
328
|
-
assert.deepEqual(report.created, []);
|
|
329
|
-
assert.deepEqual(report.errors, [], 'a project that switched the gate off has no problem to report');
|
|
298
|
+
assert.equal(created.length, 0, 'and the production table files nothing either way');
|
|
299
|
+
assert.ok(report.errors.some((e) => /artistGateMode\(\) threw/.test(e)), 'the failed read says so');
|
|
330
300
|
});
|
|
331
301
|
|
|
332
|
-
// --- the
|
|
302
|
+
// --- the changed files (task 1004201) ----------------------------------------
|
|
333
303
|
|
|
334
304
|
await test('a page file changed under modules/*/public/ is visual work whatever the label says', () => {
|
|
335
305
|
const H = cascade.hasCopyOrVisualWork;
|
|
@@ -358,67 +328,43 @@ await test('a backend file in a UI module is NOT visual work — page files only
|
|
|
358
328
|
assert.equal(H(unlabelled, null), false);
|
|
359
329
|
});
|
|
360
330
|
|
|
361
|
-
await test('the ship runner resolves the changed files ONCE and
|
|
362
|
-
const
|
|
331
|
+
await test('the ship runner resolves the changed files ONCE into ctx, and a page change files nothing', async () => {
|
|
332
|
+
const probe = ctxProbe();
|
|
363
333
|
let asked = 0;
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
};
|
|
370
|
-
const report = await cascade.runCascadesForShip({ id: '7001' }, deps);
|
|
334
|
+
const changedFiles = async () => { asked++; return { paths: ['modules/hall-ui/public/goal-forest-render.js'], truncated: true }; };
|
|
335
|
+
await cascade.runCascadesForShip({ id: '7001' }, {
|
|
336
|
+
rules: [probe.rule], getTask: async () => shippedCopy({ module_key: null }),
|
|
337
|
+
findTaskBySourceRef: async () => null, createTask: async () => ({ id: '1' }), changedFiles,
|
|
338
|
+
});
|
|
371
339
|
assert.equal(asked, 1);
|
|
372
|
-
assert.
|
|
373
|
-
assert.
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
await test('a changed-files list cut off at the read cap FILES the review — a padded PR cannot skip it', async () => {
|
|
377
|
-
const run = async (changed) => {
|
|
378
|
-
const created = [];
|
|
379
|
-
await cascade.runCascadesForShip({ id: '7001' }, {
|
|
380
|
-
getTask: async () => shippedCopy({ module_key: null, discipline: 'engineer' }),
|
|
381
|
-
findTaskBySourceRef: async () => null,
|
|
382
|
-
createTask: async (spec) => { created.push(spec); return { id: '9500' }; },
|
|
383
|
-
changedFiles: async () => changed,
|
|
384
|
-
});
|
|
385
|
-
return created.filter((s) => s.discipline === 'artist').length;
|
|
386
|
-
};
|
|
387
|
-
const padding = Array.from({ length: 300 }, (_, i) => `docs/pad-${i}.md`);
|
|
388
|
-
assert.equal(await run({ paths: padding, truncated: true }), 1);
|
|
389
|
-
assert.equal(await run({ paths: padding, truncated: false }), 0, 'the same list, complete, is not UI work');
|
|
390
|
-
});
|
|
340
|
+
assert.deepEqual(probe.seen[0].changedFiles, ['modules/hall-ui/public/goal-forest-render.js']);
|
|
341
|
+
assert.equal(probe.seen[0].changedFilesTruncated, true);
|
|
391
342
|
|
|
392
|
-
|
|
343
|
+
// The production table, on the same ship: no artist review, nothing the
|
|
344
|
+
// deploy gate would hold, no error.
|
|
393
345
|
const gate = require_(path.join(HERE, '..', '..', '..', 'src', 'bongos', 'artist-gate.js'));
|
|
394
346
|
const created = [];
|
|
395
|
-
await cascade.runCascadesForShip({ id: '7001' }, {
|
|
396
|
-
getTask: async () => shippedCopy({ module_key: null
|
|
347
|
+
const report = await cascade.runCascadesForShip({ id: '7001' }, {
|
|
348
|
+
getTask: async () => shippedCopy({ module_key: null }),
|
|
397
349
|
findTaskBySourceRef: async () => null,
|
|
398
350
|
createTask: async (spec) => { created.push(spec); return { id: '9600' }; },
|
|
399
|
-
changedFiles:
|
|
351
|
+
changedFiles, artistGateMode: () => 'strict',
|
|
400
352
|
});
|
|
401
|
-
|
|
402
|
-
assert.
|
|
403
|
-
assert.
|
|
353
|
+
assert.deepEqual(created, []);
|
|
354
|
+
assert.equal(created.some((s) => gate.isArtistReview({ source: s.source, source_ref: s.sourceRef })), false);
|
|
355
|
+
assert.deepEqual(report.errors, []);
|
|
404
356
|
});
|
|
405
357
|
|
|
406
|
-
await test('a changed-files read that fails is REPORTED, never thrown
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
};
|
|
417
|
-
const unlabelled = await run(shippedCopy({ module_key: null, discipline: 'engineer' }));
|
|
418
|
-
assert.equal(unlabelled.created.length, 0);
|
|
419
|
-
assert.match(unlabelled.report.errors.join('\n'), /changedFiles\(\) threw \(github down\)/);
|
|
420
|
-
const labelled = await run(shippedCopy({ module_key: 'hall-ui' }));
|
|
421
|
-
assert.equal(labelled.created.filter((s) => s.discipline === 'artist').length, 1, 'an outage never costs a labelled review');
|
|
358
|
+
await test('a changed-files read that fails is REPORTED, never thrown', async () => {
|
|
359
|
+
const created = [];
|
|
360
|
+
const report = await cascade.runCascadesForShip({ id: '7001' }, {
|
|
361
|
+
getTask: async () => shippedCopy(),
|
|
362
|
+
findTaskBySourceRef: async () => null,
|
|
363
|
+
createTask: async (spec) => { created.push(spec); return { id: '9400' }; },
|
|
364
|
+
changedFiles: async () => { throw new Error('github down'); },
|
|
365
|
+
});
|
|
366
|
+
assert.equal(created.length, 0);
|
|
367
|
+
assert.match(report.errors.join('\n'), /changedFiles\(\) threw \(github down\)/);
|
|
422
368
|
});
|
|
423
369
|
|
|
424
370
|
const shipFiles = require_(path.join(HERE, '..', 'ship-files.js'));
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1067",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.1067",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1067",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/release-notes.json
CHANGED
|
@@ -7691,5 +7691,17 @@
|
|
|
7691
7691
|
"id": "1004323",
|
|
7692
7692
|
"text": "An artist can now approve a tweaked page from the studio. A new Approval queue button opens a glass panel that shows the applied page as real pictures, before and after, on desktop and phone, in light and dark, with the change"
|
|
7693
7693
|
}
|
|
7694
|
+
],
|
|
7695
|
+
"1.19.1066": [
|
|
7696
|
+
{
|
|
7697
|
+
"id": "1004324",
|
|
7698
|
+
"text": "When an artist's page rewrite is approved and goes live, the artist is now paid 30 credits for it, the same value an artist review used to carry. The payment lands at the moment the page ships, never at approval, and a page th"
|
|
7699
|
+
}
|
|
7700
|
+
],
|
|
7701
|
+
"1.19.1067": [
|
|
7702
|
+
{
|
|
7703
|
+
"id": "1004325",
|
|
7704
|
+
"text": "A ship that changes a page's words no longer files an \"Artist review\" task. Those reviews came one per ship, and most were thrown away unread. Instead, the page itself shows \"changed since last tweak\" in Tweak Mode, worked out"
|
|
7705
|
+
}
|
|
7694
7706
|
]
|
|
7695
7707
|
}
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.1067'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|