@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.
@@ -1110,8 +1110,8 @@
1110
1110
  "text": "Let it be for now",
1111
1111
  "occurrences": 2,
1112
1112
  "at": [
1113
- "modules/hall-ui/public/studio.js:215",
1114
- "modules/hall-ui/public/studio.js:230"
1113
+ "modules/hall-ui/public/studio.js:218",
1114
+ "modules/hall-ui/public/studio.js:233"
1115
1115
  ]
1116
1116
  },
1117
1117
  {
@@ -2010,8 +2010,8 @@
2010
2010
  "text": "to tend now · {…}",
2011
2011
  "occurrences": 2,
2012
2012
  "at": [
2013
- "modules/hall-ui/public/studio.js:215",
2014
- "modules/hall-ui/public/studio.js:230"
2013
+ "modules/hall-ui/public/studio.js:218",
2014
+ "modules/hall-ui/public/studio.js:233"
2015
2015
  ]
2016
2016
  },
2017
2017
  {
@@ -3924,7 +3924,7 @@
3924
3924
  "surface": "builders-hall",
3925
3925
  "text": "Coach the grader",
3926
3926
  "file": "modules/hall-ui/public/studio.js",
3927
- "line": 193,
3927
+ "line": 196,
3928
3928
  "origin": "js-markup",
3929
3929
  "confidence": "certain"
3930
3930
  },
@@ -5121,7 +5121,7 @@
5121
5121
  "surface": "builders-hall",
5122
5122
  "text": "Dismissed — the copy and visuals are good as shipped.",
5123
5123
  "file": "modules/hall-ui/public/studio.js",
5124
- "line": 368,
5124
+ "line": 371,
5125
5125
  "origin": "js-notice",
5126
5126
  "confidence": "certain"
5127
5127
  },
@@ -5589,7 +5589,7 @@
5589
5589
  "surface": "builders-hall",
5590
5590
  "text": "Filed as task {…} — this review is closed against it.",
5591
5591
  "file": "modules/hall-ui/public/studio.js",
5592
- "line": 457,
5592
+ "line": 460,
5593
5593
  "origin": "js-notice",
5594
5594
  "confidence": "certain"
5595
5595
  },
@@ -6741,7 +6741,7 @@
6741
6741
  "surface": "builders-hall",
6742
6742
  "text": "It shipped and it is live. Say what you see — your review coaches the grader and never blocks what shipped.",
6743
6743
  "file": "modules/hall-ui/public/studio.js",
6744
- "line": 213,
6744
+ "line": 216,
6745
6745
  "origin": "js-markup",
6746
6746
  "confidence": "certain"
6747
6747
  },
@@ -6750,7 +6750,7 @@
6750
6750
  "surface": "builders-hall",
6751
6751
  "text": "It shipped and it is live. Your review coaches the grader on how it judged the work, then remakes or tweaks the words or art only if they need it — it never blocks what shipped.",
6752
6752
  "file": "modules/hall-ui/public/studio.js",
6753
- "line": 214,
6753
+ "line": 217,
6754
6754
  "origin": "js-markup",
6755
6755
  "confidence": "certain"
6756
6756
  },
@@ -7029,7 +7029,7 @@
7029
7029
  "surface": "builders-hall",
7030
7030
  "text": "Let it be for now",
7031
7031
  "file": "modules/hall-ui/public/studio.js",
7032
- "line": 215,
7032
+ "line": 218,
7033
7033
  "origin": "js-markup",
7034
7034
  "confidence": "certain"
7035
7035
  },
@@ -7038,7 +7038,7 @@
7038
7038
  "surface": "builders-hall",
7039
7039
  "text": "Let it be for now",
7040
7040
  "file": "modules/hall-ui/public/studio.js",
7041
- "line": 230,
7041
+ "line": 233,
7042
7042
  "origin": "js-markup",
7043
7043
  "confidence": "certain"
7044
7044
  },
@@ -7290,7 +7290,7 @@
7290
7290
  "surface": "builders-hall",
7291
7291
  "text": "Looks good",
7292
7292
  "file": "modules/hall-ui/public/studio.js",
7293
- "line": 173,
7293
+ "line": 176,
7294
7294
  "origin": "js-markup",
7295
7295
  "confidence": "certain"
7296
7296
  },
@@ -7578,7 +7578,7 @@
7578
7578
  "surface": "builders-hall",
7579
7579
  "text": "Needs work",
7580
7580
  "file": "modules/hall-ui/public/studio.js",
7581
- "line": 173,
7581
+ "line": 176,
7582
7582
  "origin": "js-markup",
7583
7583
  "confidence": "certain"
7584
7584
  },
@@ -8190,7 +8190,7 @@
8190
8190
  "surface": "builders-hall",
8191
8191
  "text": "Note it",
8192
8192
  "file": "modules/hall-ui/public/studio.js",
8193
- "line": 173,
8193
+ "line": 176,
8194
8194
  "origin": "js-markup",
8195
8195
  "confidence": "certain"
8196
8196
  },
@@ -8199,7 +8199,7 @@
8199
8199
  "surface": "builders-hall",
8200
8200
  "text": "Noted on the review — it stays open.",
8201
8201
  "file": "modules/hall-ui/public/studio.js",
8202
- "line": 400,
8202
+ "line": 403,
8203
8203
  "origin": "js-notice",
8204
8204
  "confidence": "certain"
8205
8205
  },
@@ -8406,7 +8406,7 @@
8406
8406
  "surface": "builders-hall",
8407
8407
  "text": "Only if it needs it — with the AI at your side, or on your own.",
8408
8408
  "file": "modules/hall-ui/public/studio.js",
8409
- "line": 193,
8409
+ "line": 196,
8410
8410
  "origin": "js-markup",
8411
8411
  "confidence": "certain"
8412
8412
  },
@@ -8532,7 +8532,7 @@
8532
8532
  "surface": "builders-hall",
8533
8533
  "text": "Open in the copy desk",
8534
8534
  "file": "modules/hall-ui/public/studio.js",
8535
- "line": 230,
8535
+ "line": 233,
8536
8536
  "origin": "js-markup",
8537
8537
  "confidence": "certain"
8538
8538
  },
@@ -8604,7 +8604,7 @@
8604
8604
  "surface": "builders-hall",
8605
8605
  "text": "Open this review",
8606
8606
  "file": "modules/hall-ui/public/studio.js",
8607
- "line": 215,
8607
+ "line": 218,
8608
8608
  "origin": "js-markup",
8609
8609
  "confidence": "certain"
8610
8610
  },
@@ -9450,7 +9450,7 @@
9450
9450
  "surface": "builders-hall",
9451
9451
  "text": "Remake or tweak",
9452
9452
  "file": "modules/hall-ui/public/studio.js",
9453
- "line": 193,
9453
+ "line": 196,
9454
9454
  "origin": "js-markup",
9455
9455
  "confidence": "certain"
9456
9456
  },
@@ -9765,7 +9765,7 @@
9765
9765
  "surface": "builders-hall",
9766
9766
  "text": "Review how it judged this work, and teach it what good looked like.",
9767
9767
  "file": "modules/hall-ui/public/studio.js",
9768
- "line": 193,
9768
+ "line": 196,
9769
9769
  "origin": "js-markup",
9770
9770
  "confidence": "certain"
9771
9771
  },
@@ -10602,7 +10602,7 @@
10602
10602
  "surface": "builders-hall",
10603
10603
  "text": "Start over",
10604
10604
  "file": "modules/hall-ui/public/studio.js",
10605
- "line": 246,
10605
+ "line": 249,
10606
10606
  "origin": "js-markup",
10607
10607
  "confidence": "certain"
10608
10608
  },
@@ -11133,7 +11133,7 @@
11133
11133
  "surface": "builders-hall",
11134
11134
  "text": "The headline lands, but the sub-line reads like a brochure.",
11135
11135
  "file": "modules/hall-ui/public/studio.js",
11136
- "line": 173,
11136
+ "line": 176,
11137
11137
  "origin": "js-markup",
11138
11138
  "confidence": "certain"
11139
11139
  },
@@ -12636,7 +12636,7 @@
12636
12636
  "surface": "builders-hall",
12637
12637
  "text": "What you saw",
12638
12638
  "file": "modules/hall-ui/public/studio.js",
12639
- "line": 173,
12639
+ "line": 176,
12640
12640
  "origin": "js-markup",
12641
12641
  "confidence": "certain"
12642
12642
  },
@@ -13284,7 +13284,7 @@
13284
13284
  "surface": "builders-hall",
13285
13285
  "text": "Your verdict on a review is recorded from the review itself — open it to dismiss it, note what you saw, or file the follow-up.",
13286
13286
  "file": "modules/hall-ui/public/studio.js",
13287
- "line": 170,
13287
+ "line": 173,
13288
13288
  "origin": "js-markup",
13289
13289
  "confidence": "certain"
13290
13290
  },
@@ -13482,7 +13482,7 @@
13482
13482
  "surface": "builders-hall",
13483
13483
  "text": "and {…} more waiting{…}",
13484
13484
  "file": "modules/hall-ui/public/studio.js",
13485
- "line": 288,
13485
+ "line": 291,
13486
13486
  "origin": "js-markup",
13487
13487
  "confidence": "certain"
13488
13488
  },
@@ -15300,7 +15300,7 @@
15300
15300
  "surface": "builders-hall",
15301
15301
  "text": "to tend now · {…}",
15302
15302
  "file": "modules/hall-ui/public/studio.js",
15303
- "line": 215,
15303
+ "line": 218,
15304
15304
  "origin": "js-markup",
15305
15305
  "confidence": "certain"
15306
15306
  },
@@ -15309,7 +15309,7 @@
15309
15309
  "surface": "builders-hall",
15310
15310
  "text": "to tend now · {…}",
15311
15311
  "file": "modules/hall-ui/public/studio.js",
15312
- "line": 230,
15312
+ "line": 233,
15313
15313
  "origin": "js-markup",
15314
15314
  "confidence": "certain"
15315
15315
  },
@@ -16299,7 +16299,7 @@
16299
16299
  "surface": "builders-hall",
16300
16300
  "text": "— your words, in your voice. Needed for a note or a follow-up.",
16301
16301
  "file": "modules/hall-ui/public/studio.js",
16302
- "line": 173,
16302
+ "line": 176,
16303
16303
  "origin": "js-markup",
16304
16304
  "confidence": "certain"
16305
16305
  },
@@ -2617,5 +2617,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
2617
2617
  landed since 1.19.1063 with no explicit bump. run 36441707814. (task 1002620)
2618
2618
  1.19.1065 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2619
2619
  landed since 1.19.1064 with no explicit bump. run 36451089716. (task 1002620)
2620
+ 1.19.1066 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2621
+ landed since 1.19.1065 with no explicit bump. run 36454504693. (task 1002620)
2622
+ 1.19.1067 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2623
+ landed since 1.19.1066 with no explicit bump. run 36458843914. (task 1002620)
2620
2624
  ---------------------------------------------------------------------------
2621
2625
  ```
@@ -2651,7 +2651,7 @@
2651
2651
  "surface": "builders",
2652
2652
  "title": "Studio",
2653
2653
  "states_read": ["focus","out","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back"],
2654
- "files_hash": "e1041dfa74aca8dd",
2654
+ "files_hash": "30f4407e6abacbb0",
2655
2655
  "reading_hash": "e52bb7163191d85a",
2656
2656
  "counts": {"lines":45,"placed":23,"shared":5,"unplaced":17},
2657
2657
  "omitted": {"data":7},
@@ -2667,18 +2667,18 @@
2667
2667
  {"key":"L0008","section":"Good morning, {…}","text":"Approval queue","placement":"placed","file":"modules/hall-ui/public/studio.html","line":55,"string_id":"20c98a4b630f"},
2668
2668
  {"key":"L0009","section":"Good morning, {…}","text":"1 page applied, waiting for you","placement":"unplaced","state":"approved"},
2669
2669
  {"key":"L0010","section":"Good morning, {…}","text":"2 pages applied, waiting for you","placement":"unplaced"},
2670
- {"key":"L0011","section":"Good morning, {…}","text":"to tend now · {…}","placement":"placed","file":"modules/hall-ui/public/studio.js","line":215,"string_id":"1b88ce51fd84"},
2670
+ {"key":"L0011","section":"Good morning, {…}","text":"to tend now · {…}","placement":"placed","file":"modules/hall-ui/public/studio.js","line":218,"string_id":"1b88ce51fd84"},
2671
2671
  {"key":"L0012","section":"The copy and visuals that {…} in task #1899","text":"The copy and visuals that {…} in task #1899","placement":"unplaced"},
2672
- {"key":"L0013","section":"The copy and visuals that {…} in task #1899","text":"It shipped and it is live. Say what you see — your review coaches the grader and never blocks what shipped.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":213,"string_id":"a28aa368453f"},
2673
- {"key":"L0014","section":"The copy and visuals that {…} in task #1899","text":"What you saw","placement":"placed","file":"modules/hall-ui/public/studio.js","line":173,"string_id":"1d5bfd09068c"},
2674
- {"key":"L0015","section":"The copy and visuals that {…} in task #1899","text":"— your words, in your voice. Needed for a note or a follow-up.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":173,"string_id":"d3afa6d6dd9e"},
2675
- {"key":"L0016","section":"The copy and visuals that {…} in task #1899","text":"The headline lands, but the sub-line reads like a brochure.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":173,"string_id":"027e9420daa2","attr":"placeholder"},
2676
- {"key":"L0017","section":"The copy and visuals that {…} in task #1899","text":"Looks good","placement":"placed","file":"modules/hall-ui/public/studio.js","line":173,"string_id":"73677b6839d7"},
2677
- {"key":"L0018","section":"The copy and visuals that {…} in task #1899","text":"Note it","placement":"placed","file":"modules/hall-ui/public/studio.js","line":173,"string_id":"73c72974f4f9"},
2678
- {"key":"L0019","section":"The copy and visuals that {…} in task #1899","text":"Needs work","placement":"placed","file":"modules/hall-ui/public/studio.js","line":173,"string_id":"3970d299c95a"},
2679
- {"key":"L0020","section":"The copy and visuals that {…} in task #1899","text":"Open this review","placement":"placed","file":"modules/hall-ui/public/studio.js","line":215,"string_id":"1cb80282de09"},
2680
- {"key":"L0021","section":"The copy and visuals that {…} in task #1899","text":"Let it be for now","placement":"placed","file":"modules/hall-ui/public/studio.js","line":215,"string_id":"d6a78b9e5368"},
2681
- {"key":"L0022","section":"The copy and visuals that {…} in task #1899","text":"and {…} more waiting{…}","placement":"placed","file":"modules/hall-ui/public/studio.js","line":288,"string_id":"d86265f99668"},
2672
+ {"key":"L0013","section":"The copy and visuals that {…} in task #1899","text":"It shipped and it is live. Say what you see — your review coaches the grader and never blocks what shipped.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":216,"string_id":"a28aa368453f"},
2673
+ {"key":"L0014","section":"The copy and visuals that {…} in task #1899","text":"What you saw","placement":"placed","file":"modules/hall-ui/public/studio.js","line":176,"string_id":"1d5bfd09068c"},
2674
+ {"key":"L0015","section":"The copy and visuals that {…} in task #1899","text":"— your words, in your voice. Needed for a note or a follow-up.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":176,"string_id":"d3afa6d6dd9e"},
2675
+ {"key":"L0016","section":"The copy and visuals that {…} in task #1899","text":"The headline lands, but the sub-line reads like a brochure.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":176,"string_id":"027e9420daa2","attr":"placeholder"},
2676
+ {"key":"L0017","section":"The copy and visuals that {…} in task #1899","text":"Looks good","placement":"placed","file":"modules/hall-ui/public/studio.js","line":176,"string_id":"73677b6839d7"},
2677
+ {"key":"L0018","section":"The copy and visuals that {…} in task #1899","text":"Note it","placement":"placed","file":"modules/hall-ui/public/studio.js","line":176,"string_id":"73c72974f4f9"},
2678
+ {"key":"L0019","section":"The copy and visuals that {…} in task #1899","text":"Needs work","placement":"placed","file":"modules/hall-ui/public/studio.js","line":176,"string_id":"3970d299c95a"},
2679
+ {"key":"L0020","section":"The copy and visuals that {…} in task #1899","text":"Open this review","placement":"placed","file":"modules/hall-ui/public/studio.js","line":218,"string_id":"1cb80282de09"},
2680
+ {"key":"L0021","section":"The copy and visuals that {…} in task #1899","text":"Let it be for now","placement":"placed","file":"modules/hall-ui/public/studio.js","line":218,"string_id":"d6a78b9e5368"},
2681
+ {"key":"L0022","section":"The copy and visuals that {…} in task #1899","text":"and {…} more waiting{…}","placement":"placed","file":"modules/hall-ui/public/studio.js","line":291,"string_id":"d86265f99668"},
2682
2682
  {"key":"L0023","section":"The copy and visuals that {…} in task #1899","text":"The copy desk — every flagged string","placement":"placed","file":"modules/hall-ui/public/studio.html","line":76,"string_id":"2dc061096c48"},
2683
2683
  {"key":"L0024","section":"The copy and visuals that {…} in task #1899","text":"The task board — all work","placement":"placed","file":"modules/hall-ui/public/studio.html","line":77,"string_id":"599fd0e82d1c"},
2684
2684
  {"key":"L0025","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":473,"string_id":"1883ad7f07fc"},
@@ -36,8 +36,10 @@ const pages = require('./pages');
36
36
 
37
37
  const TERMINAL = new Set(['shipped', 'abandoned']);
38
38
 
39
- // The credit reason ADR 0341 D10 books an approved page under. TW13 writes it;
40
- // until then no row carries it and every tally reads 0, which is the truth.
39
+ // The credit reason ADR 0341 D10 books an approved page under. The economy
40
+ // module writes it at the land (credits.js awardArtistPageCredit, task 1004324,
41
+ // its ARTIST_PAGE_REASON_PREFIX); restated here because a module cannot require
42
+ // another, and tests/artist_page_credit.mjs holds the two strings together.
41
43
  const TALLY_REASON_PREFIX = 'tweak.page_approved:';
42
44
  const WEEK_MS = 7 * 24 * 60 * 60 * 1000;
43
45
 
@@ -361,8 +361,9 @@ function pageReadsOrFail(res) {
361
361
  }
362
362
 
363
363
  // Every `tweak.page_approved:` credit row the caller has, through the reward
364
- // port (credit_log is economy's table). No reward port, or no rows yet (TW13
365
- // has not built the payout), reads as none: a tally of 0 is the truth then.
364
+ // port (credit_log is economy's table). No reward port, or no approved page
365
+ // landed yet (economy books one row per landed round, task 1004324), reads as
366
+ // none: a tally of 0 is the truth then.
366
367
  //
367
368
  // ONE bounded query. An approved page books one row, so the cap is thousands of
368
369
  // pages for one artist; past it the tally says `truncated` (creditLedger's
@@ -1174,6 +1174,80 @@ async function sumSessionEarnings(executor, builderId, taskIds, sessionId) {
1174
1174
  return rows[0] ? rows[0].total : 0;
1175
1175
  }
1176
1176
 
1177
+ // =========================================================================
1178
+ // The ARTIST credit lane (task 1004324 / BV2.TW13, ADR 0341 D10).
1179
+ // =========================================================================
1180
+ // Tweak Mode replaced the per-ship artist review with an approved page, and the
1181
+ // owner's rule is the same payouts. A review paid its PRICED value,
1182
+ // credits_reward x kind multiplier, as the per-task estimate, which cost-plus-only
1183
+ // withholds, so paid literally a studio artist would earn nothing on this
1184
+ // instance. So an approved page pays that priced value (30 for a feature round
1185
+ // at 30) on its own lane, `artistCredit`, which cost-plus-only does not touch:
1186
+ // the ideator lane's precedent (ADR 0172). The lifecycle calls this at the land
1187
+ // INSTEAD of the shipper's per-task estimate, so the total is conserved in both
1188
+ // modes, and the applier keeps its cost-plus session reward, which is booked
1189
+ // elsewhere and is untouched here.
1190
+ //
1191
+ // The reason prefix is the one copy-desk's tally already sums
1192
+ // (modules/copy-desk/page-status.js TALLY_REASON_PREFIX, restated there because
1193
+ // a module cannot require another; tests/artist_page_credit.mjs holds the two
1194
+ // strings together).
1195
+ const ARTIST_PAGE_REASON_PREFIX = 'tweak.page_approved:';
1196
+ const PAGE_TWEAK_SOURCE = 'page-tweak';
1197
+
1198
+ // Everything is read from the ledger inside the caller's transaction, never
1199
+ // taken from the caller (ADR 0185): the task's own source, status and priced
1200
+ // value, and the payee, the builder of the round's LATEST WEB claim (both
1201
+ // worktree_name and creator_session_id null), the claim the submit released.
1202
+ // That is the TW05 reads' artist rule (modules/lifecycle/page-tweak-reads.js),
1203
+ // so the changelog's artist and the paid artist are the same person.
1204
+ //
1205
+ // NEVER PAID UNLESS SHIPPED. The row must read `shipped` in this transaction, so
1206
+ // a round that was sent back, abandoned or is still waiting pays nothing, even
1207
+ // if a caller reaches this early.
1208
+ //
1209
+ // ONE PAYMENT PER ROUND. The NOT EXISTS keys on (task_id, reason), served by
1210
+ // idx_credit_log_task. That is stricter than ADR 0341's "(builder, reason)": a
1211
+ // round has one payee, so keying on the round alone also refuses a second row
1212
+ // should the payee ever read differently on a re-sweep, and a self-applied round
1213
+ // (the artist also ran /tweak) is still one artist row, never two.
1214
+ //
1215
+ // Returns { credited, reason, artistId, delta } with a reason on every path:
1216
+ // 'paid' · 'already_paid' · 'artist_lane_off' · 'not_found' · 'not_a_page_tweak'
1217
+ // · 'not_shipped' · 'no_artist' · 'zero_value'.
1218
+ async function awardArtistPageCredit(client, { taskId, config = rewardConfig() } = {}) {
1219
+ if (config && config.artistCredit === false) return { credited: 0, reason: 'artist_lane_off' };
1220
+ const { rows } = await client.query(
1221
+ `SELECT t.source, t.status, t.credits_reward, t.kind,
1222
+ (SELECT c.builder_id FROM claims c
1223
+ WHERE c.task_id = t.id AND c.worktree_name IS NULL AND c.creator_session_id IS NULL
1224
+ ORDER BY c.claimed_at DESC, c.id DESC
1225
+ LIMIT 1) AS artist_id
1226
+ FROM tasks t
1227
+ WHERE t.id = $1`,
1228
+ [taskId]
1229
+ );
1230
+ const t = rows[0];
1231
+ if (!t) return { credited: 0, reason: 'not_found' };
1232
+ if (t.source !== PAGE_TWEAK_SOURCE) return { credited: 0, reason: 'not_a_page_tweak' };
1233
+ if (t.status !== 'shipped') return { credited: 0, reason: 'not_shipped' };
1234
+ if (t.artist_id == null) return { credited: 0, reason: 'no_artist' };
1235
+ // The review's priced value, by the one multiplier rule (rounded once, there).
1236
+ const priced = applyKindMultiplier(t.credits_reward, t.kind);
1237
+ if (priced.effective <= 0) return { credited: 0, reason: 'zero_value', artistId: t.artist_id };
1238
+ const reason = `${ARTIST_PAGE_REASON_PREFIX}${taskId}`;
1239
+ const { rowCount } = await client.query(
1240
+ `INSERT INTO credit_log (builder_id, task_id, delta, reason, description)
1241
+ SELECT $1, $2, $3, $4, $5
1242
+ WHERE NOT EXISTS (SELECT 1 FROM credit_log WHERE task_id = $2 AND reason = $4)`,
1243
+ [t.artist_id, taskId, priced.effective, reason,
1244
+ `Approved page tweak, task #${taskId}: ${priced.description} to its artist (artist lane, ADR 0341 D10)`]
1245
+ );
1246
+ return rowCount > 0
1247
+ ? { credited: priced.effective, reason: 'paid', artistId: t.artist_id, delta: priced.effective }
1248
+ : { credited: 0, reason: 'already_paid', artistId: t.artist_id, delta: priced.effective };
1249
+ }
1250
+
1177
1251
  // The three ideator streams (ADR 0172) each book under a reason key that EMBEDS
1178
1252
  // the idea (and, for stream 1, the task) — that string IS the idempotency
1179
1253
  // predicate, which is why it can't be a bare constant:
@@ -1294,4 +1368,7 @@ module.exports = {
1294
1368
  // the ledger read surface (task 1003484, blocker 1000127)
1295
1369
  creditLedger,
1296
1370
  IDEA_STREAM_REASON_PREFIXES,
1371
+ // the artist lane (task 1004324 / BV2.TW13, ADR 0341 D10)
1372
+ awardArtistPageCredit,
1373
+ ARTIST_PAGE_REASON_PREFIX,
1297
1374
  };
@@ -61,6 +61,12 @@ function rewardPolicy(rawReward) {
61
61
  const perTaskCredit = mode !== REWARD_MODE_COST_PLUS_ONLY;
62
62
  // Default-on, opt-out-only: only an explicit `false` withholds the ideator lane.
63
63
  const ideatorCredit = r.ideatorCredit !== false;
64
+ // The ARTIST lane (task 1004324 / BV2.TW13, ADR 0341 D10): an approved page
65
+ // pays its artist on its own lane, the ideator lane's precedent exactly. Not
66
+ // derived from `mode`, so cost-plus-only does not withhold it: a studio artist
67
+ // runs no session, so the cost-plus reward can never reach them. Default-on,
68
+ // opt-out-only, the same rule as ideatorCredit.
69
+ const artistCredit = r.artistCredit !== false;
64
70
  // Validated to [0, 1): see IDEA_DESCENT_DECAY above — a rate of 1 or more does
65
71
  // not converge, and a negative one would pay a descent backwards.
66
72
  // ABSENT IS THE DEFAULT, NOT ZERO — and Number(null) is 0, which is a legal
@@ -71,7 +77,7 @@ function rewardPolicy(rawReward) {
71
77
  const ideaDescentDecay = Number.isFinite(rawDecay) && rawDecay >= 0 && rawDecay < 1
72
78
  ? rawDecay
73
79
  : IDEA_DESCENT_DECAY;
74
- return { marginPct, usdPeg, mode, perTaskCredit, ideatorCredit, ideaDescentDecay };
80
+ return { marginPct, usdPeg, mode, perTaskCredit, ideatorCredit, artistCredit, ideaDescentDecay };
75
81
  }
76
82
 
77
83
  module.exports = {
@@ -40,6 +40,10 @@ module.exports = {
40
40
  // `client` (docs/specs/board-room-pass-event-contract.md) — the port is how
41
41
  // money crosses the wall; the `board.item.passed` event never carries a payment.
42
42
  awardIdeaGovernancePassCredit: (...a) => credits.awardIdeaGovernancePassCredit(...a),
43
+ // BV2.TW13 / ADR 0341 D10 — the artist lane: an approved page, at its land,
44
+ // pays its artist the review's priced value. The lifecycle's landing hook calls
45
+ // it INSTEAD of the per-task estimate on a page tweak; the payee is read here.
46
+ awardArtistPageCredit: (...a) => credits.awardArtistPageCredit(...a),
43
47
  awardNetNegativeBonus: (...a) => credits.awardNetNegativeBonus(...a),
44
48
  awardSessionTokenReward: (...a) => credits.awardSessionTokenReward(...a),
45
49
  // gamification hooks the lifecycle fires at claim/ship
@@ -97,6 +97,6 @@
97
97
  studio.js mounts it with its own WRITE_ROUTES. -->
98
98
  <script src="/builders/approval-queue-lib.js"></script>
99
99
  <script src="/builders/approval-queue.js"></script>
100
- <script src="/builders/studio.js?v=2026-09-28-approvals"></script>
100
+ <script src="/builders/studio.js?v=2026-09-28-tw14"></script>
101
101
  </body>
102
102
  </html>
@@ -8,10 +8,13 @@
8
8
  // So this is NOT a queue table. It aggregates the artist's real work — the two
9
9
  // surfaces the rest of goal 1000074 built — and presents it ONE PIECE AT A TIME,
10
10
  // a stone to tend in a calm garden, with the rest waiting quietly:
11
- // 1. REVIEW REQUESTS (R04, cascade.js) — a copy/visual ship files a two-step
12
- // artist review at `backlog`, discipline 'artist', source 'cascade'. The
13
- // two steps (coach the grader, then remake/tweak) live on the task record;
14
- // this room names them and opens the door.
11
+ // 1. REVIEW REQUESTS (R04, cascade.js) — RETIRED, draining. A copy/visual
12
+ // ship used to file a two-step artist review at `backlog`, discipline
13
+ // 'artist', source 'cascade'. Tweak Mode removed that rule (task 1004325 /
14
+ // BV2.TW14, ADR 0341 D9), so no new reviews arrive; the ones already filed
15
+ // still show here so they can be answered (they may still hold a deploy
16
+ // under the strict artist gate, ADR 0241). TW16 rebuilds this room as the
17
+ // Tweak Mode home, and this queue goes with it once it is empty.
15
18
  // 2. FLAGGED COPY (R02, copy-desk) — open flags over the words the product
16
19
  // shows people. Best-effort: an instance without the copy-desk module has
17
20
  // no queue, and the room degrades to reviews alone rather than erroring.
@@ -46,9 +49,9 @@
46
49
  let busy = false; // a verdict is in flight — one at a time, so a double-click cannot file twice
47
50
  let tended = false; // at least one verdict landed this sitting, so an emptied garden reads as finished
48
51
 
49
- // Bound the reviews read. cascade.js files a review per qualifying ship and they
50
- // sit at backlog until claimed or dismissed ("dismissable rather than nagging"),
51
- // so this queue grows without bound over the project's life — the unbounded-read
52
+ // Bound the reviews read. cascade.js USED to file a review per qualifying ship
53
+ // (no longer, since TW14: the queue only drains now), and they sit at backlog
54
+ // until claimed or dismissed, so this queue could grow without bound — the unbounded-read
52
55
  // shape modules/hall-ui/CLAUDE.md flags as a repeat bug (the Work board's backlog,
53
56
  // Home's next-up card, the Goals rollup all had it). 50 is far more than a focus
54
57
  // queue tends at once; the footer links to the copy desk and board are the
@@ -240,8 +243,8 @@
240
243
  function emptyCard(done) {
241
244
  const heading = done ? 'You have tended everything waiting' : 'Nothing waits right now';
242
245
  const body = done
243
- ? 'That is the whole garden. Come back when work ships, or start again from the top.'
244
- : 'A quiet moment — either good news or an unread queue. When work with copy or visuals ships, a review appears here for you.';
246
+ ? 'That is the whole garden. Come back when someone flags a line, or start again from the top.'
247
+ : 'A quiet moment. When someone flags a line of copy, it waits here for you.';
245
248
  const restart = done
246
249
  ? '<div class="studio-card__actions studio-empty__actions"><button type="button" class="btn-ghost" data-restart>Start over</button></div>'
247
250
  : '';