@bongos/core 1.20.58 → 1.20.59
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 +80 -40
- package/clients/bongos-client/index.d.ts +2 -2
- package/docs/api/openapi.json +9 -3
- package/docs/api-reference.md +1 -1
- package/docs/architecture.md +1 -0
- package/docs/copy-inventory.md +1 -1
- package/docs/copy-registry.json +9 -9
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-readings.json +30 -30
- package/migrations/core_268_builders_main_discipline.sql +35 -0
- package/modules/copy-desk/artist-stats.js +56 -0
- package/modules/copy-desk/module.json +1 -1
- package/modules/copy-desk/page-status.js +39 -0
- package/modules/copy-desk/routes/copy-desk.js +7 -16
- package/modules/copy-desk/tests/copy_no_cms.mjs +10 -1
- package/modules/economy/credits-by-craft.js +208 -0
- package/modules/economy/reward.js +8 -0
- package/modules/hall-ui/public/hall-render.js +2 -2
- package/modules/hall-ui/public/profile.js +1 -1
- package/modules/ideas/ideator-stats.js +149 -0
- package/modules/ideas/module.json +2 -1
- package/modules/ideas/routes/inbox.js +7 -0
- package/modules/lifecycle/activity.js +5 -2
- package/modules/lifecycle/db-analytics.js +4 -2
- package/modules/lifecycle/db-tasks.js +49 -1
- package/modules/lifecycle/db.js +3 -2
- package/modules/lifecycle/page-tweak-reads.js +23 -5
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/scripts/gds/run-unit-tests.js +5 -0
- package/src/bongos/db.js +44 -6
- package/src/bongos/role-stats.js +155 -0
- package/src/bongos/routes/builders.js +15 -2
- package/src/bongos/routes/me.js +11 -3
- package/src/module-api.js +1 -1
- package/tests/copy_desk_page_reads.mjs +1 -1
- package/tests/fixtures/page-ledger.mjs +1 -1
- package/tests/main_discipline.mjs +81 -0
- package/tests/profile_role_stats.mjs +416 -0
- package/tests/role_stats_db.mjs +237 -0
- package/tests/tweak_replaces_artist_review.mjs +1 -1
package/docs/page-readings.json
CHANGED
|
@@ -1364,8 +1364,8 @@
|
|
|
1364
1364
|
"surface": "builders",
|
|
1365
1365
|
"title": "Builders' Hall",
|
|
1366
1366
|
"states_read": ["home","standing","standing-karma","out","founding","genesis","decide"],
|
|
1367
|
-
"files_hash": "
|
|
1368
|
-
"reading_hash": "
|
|
1367
|
+
"files_hash": "72ac47e1841830d9",
|
|
1368
|
+
"reading_hash": "1debe0f979ce3b59",
|
|
1369
1369
|
"counts": {"lines":204,"placed":68,"shared":7,"unplaced":129},
|
|
1370
1370
|
"omitted": {"data":182},
|
|
1371
1371
|
"notes": ["founding: an action failed (page.focus: Timeout 6000ms exceeded.); read as it stood"],
|
|
@@ -1408,7 +1408,7 @@
|
|
|
1408
1408
|
{"key":"L0036","section":"Needs your attention13","text":"Needs your attention","placement":"placed","file":"modules/hall-ui/public/goal-inbox.js","line":597,"string_id":"7def635421ea"},
|
|
1409
1409
|
{"key":"L0037","section":"From the system","text":"From the system","placement":"placed","file":"modules/hall-ui/public/hall-render.js","line":707,"string_id":"d32c5e058d1e"},
|
|
1410
1410
|
{"key":"L0038","section":"From the system","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":2},
|
|
1411
|
-
{"key":"L0039","section":"From the system","text":"Open
|
|
1411
|
+
{"key":"L0039","section":"From the system","text":"Open {…}","placement":"placed","file":"modules/hall-ui/public/goals.js","line":67,"string_id":"f6f68ba322be"},
|
|
1412
1412
|
{"key":"L0040","section":"Ideas awaiting triage 151","text":"Ideas awaiting triage","placement":"placed","file":"modules/hall-ui/public/builders.js","line":897,"string_id":"e181637c5a5e"},
|
|
1413
1413
|
{"key":"L0041","section":"Ideas awaiting triage 151","text":"Triage","placement":"unplaced","occurrences":5},
|
|
1414
1414
|
{"key":"L0042","section":"Ideas awaiting triage 151","text":"…{…} more open ideas — triage clears them one at a time.","placement":"placed","file":"modules/hall-ui/public/builders.js","line":895,"string_id":"e35f11bdc5d7"},
|
|
@@ -1424,17 +1424,17 @@
|
|
|
1424
1424
|
{"key":"L0052","section":"Stuck on the owner 3","text":"Filed {…} · Blocking 1 task:","placement":"unplaced"},
|
|
1425
1425
|
{"key":"L0053","section":"Your work","text":"Your work","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":101,"string_id":"60550f388cc9"},
|
|
1426
1426
|
{"key":"L0054","section":"Your work","text":"Window","placement":"unplaced","state":"standing"},
|
|
1427
|
-
{"key":"L0055","section":"Your work","text":"Last 7 days","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1428
|
-
{"key":"L0056","section":"Your work","text":"Last 30 days","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1429
|
-
{"key":"L0057","section":"Your work","text":"Last 90 days","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1430
|
-
{"key":"L0058","section":"Your work","text":"All time","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1427
|
+
{"key":"L0055","section":"Your work","text":"Last 7 days","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":129,"string_id":"9be8b839eff8","state":"standing"},
|
|
1428
|
+
{"key":"L0056","section":"Your work","text":"Last 30 days","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":129,"string_id":"35a15eb0a117","state":"standing"},
|
|
1429
|
+
{"key":"L0057","section":"Your work","text":"Last 90 days","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":130,"string_id":"59f0bc78a28f","state":"standing"},
|
|
1430
|
+
{"key":"L0058","section":"Your work","text":"All time","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":130,"string_id":"627c683a5e5d","state":"standing"},
|
|
1431
1431
|
{"key":"L0059","section":"Your work","text":"Version","placement":"unplaced","state":"standing"},
|
|
1432
|
-
{"key":"L0060","section":"Your work","text":"— any —","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1432
|
+
{"key":"L0060","section":"Your work","text":"— any —","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":132,"string_id":"729d4ce22b99","state":"standing"},
|
|
1433
1433
|
{"key":"L0061","section":"Your work","text":"Sort","placement":"unplaced","state":"standing"},
|
|
1434
|
-
{"key":"L0062","section":"Your work","text":"most recent first","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1435
|
-
{"key":"L0063","section":"Your work","text":"oldest first","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1436
|
-
{"key":"L0064","section":"Your work","text":"highest credits","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1437
|
-
{"key":"L0065","section":"Your work","text":"lowest credits","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1434
|
+
{"key":"L0062","section":"Your work","text":"most recent first","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":134,"string_id":"70c234985d42","state":"standing"},
|
|
1435
|
+
{"key":"L0063","section":"Your work","text":"oldest first","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":134,"string_id":"759c12b5f983","state":"standing"},
|
|
1436
|
+
{"key":"L0064","section":"Your work","text":"highest credits","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":135,"string_id":"55d673a5f0ec","state":"standing"},
|
|
1437
|
+
{"key":"L0065","section":"Your work","text":"lowest credits","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":136,"string_id":"754bdec368ed","state":"standing"},
|
|
1438
1438
|
{"key":"L0066","section":"Your work","text":"30 works {…}","placement":"unplaced","state":"standing"},
|
|
1439
1439
|
{"key":"L0067","section":"Your work","text":"Work","placement":"unplaced","state":"standing"},
|
|
1440
1440
|
{"key":"L0068","section":"Your work","text":"Credits","placement":"unplaced","state":"standing"},
|
|
@@ -1450,20 +1450,20 @@
|
|
|
1450
1450
|
{"key":"L0078","section":"Reviews","text":"Score","placement":"unplaced","state":"standing"},
|
|
1451
1451
|
{"key":"L0079","section":"Reviews","text":"Verdict","placement":"unplaced","state":"standing"},
|
|
1452
1452
|
{"key":"L0080","section":"Reviews","text":"Reviewed","placement":"unplaced","state":"standing"},
|
|
1453
|
-
{"key":"L0081","section":"Reviews","text":"No work reviewed yet.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1453
|
+
{"key":"L0081","section":"Reviews","text":"No work reviewed yet.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":150,"string_id":"4654849396a3","state":"standing"},
|
|
1454
1454
|
{"key":"L0082","section":"Karma","text":"Karma","placement":"unplaced","state":"standing"},
|
|
1455
1455
|
{"key":"L0083","section":"Karma","text":"Karma rewards good citizenship — ratified {…}, peer recognition, approvals. Distinct from {…}, which counts work {…}.","placement":"unplaced","state":"standing"},
|
|
1456
1456
|
{"key":"L0084","section":"Karma","text":"When","placement":"unplaced","state":"standing"},
|
|
1457
1457
|
{"key":"L0085","section":"Karma","text":"Delta","placement":"unplaced","state":"standing"},
|
|
1458
1458
|
{"key":"L0086","section":"Karma","text":"Reason","placement":"unplaced","state":"standing"},
|
|
1459
|
-
{"key":"L0087","section":"Karma","text":"Granted by","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1459
|
+
{"key":"L0087","section":"Karma","text":"Granted by","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":162,"string_id":"721fe281f993","state":"standing"},
|
|
1460
1460
|
{"key":"L0088","section":"Karma","text":"— all builders —","placement":"placed","file":"modules/hall-ui/public/builders.js","line":711,"string_id":"a6ae9cbdee30","state":"standing"},
|
|
1461
|
-
{"key":"L0089","section":"Peer recognition","text":"Peer recognition","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1462
|
-
{"key":"L0090","section":"Peer recognition","text":"Recognize your peers’ finished work. A vote up (+) or down (−) shapes their karma after a one-week cooling period. You can’t vote on your own work.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1461
|
+
{"key":"L0089","section":"Peer recognition","text":"Peer recognition","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":168,"string_id":"54fa47e421a5","state":"standing"},
|
|
1462
|
+
{"key":"L0090","section":"Peer recognition","text":"Recognize your peers’ finished work. A vote up (+) or down (−) shapes their karma after a one-week cooling period. You can’t vote on your own work.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":169,"string_id":"cd2bffe2e5b9","state":"standing"},
|
|
1463
1463
|
{"key":"L0091","section":"Peer recognition","text":"Work","placement":"unplaced","state":"standing"},
|
|
1464
1464
|
{"key":"L0092","section":"Peer recognition","text":"By","placement":"unplaced","state":"standing"},
|
|
1465
1465
|
{"key":"L0093","section":"Peer recognition","text":"Votes","placement":"unplaced","state":"standing"},
|
|
1466
|
-
{"key":"L0094","section":"Peer recognition","text":"Your vote","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1466
|
+
{"key":"L0094","section":"Peer recognition","text":"Your vote","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":170,"string_id":"f6b12676169b","state":"standing"},
|
|
1467
1467
|
{"key":"L0095","section":"Peer recognition","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","state":"standing","occurrences":9},
|
|
1468
1468
|
{"key":"L0096","section":"Peer recognition","text":"not graded","placement":"placed","file":"modules/hall-ui/public/hall-render.js","line":346,"string_id":"7b5ad068dc26","state":"standing","occurrences":10},
|
|
1469
1469
|
{"key":"L0097","section":"Peer recognition","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","state":"standing"},
|
|
@@ -1472,7 +1472,7 @@
|
|
|
1472
1472
|
{"key":"L0100","section":"Peer recognition","text":"Page {…} of {…}","placement":"placed","file":"modules/hall-ui/public/hall-kit.js","line":112,"string_id":"15a49bf15007","state":"standing"},
|
|
1473
1473
|
{"key":"L0101","section":"Peer recognition","text":"Next ›","placement":"placed","file":"modules/hall-ui/public/hall-kit.js","line":74,"string_id":"f52ba261d930","state":"standing"},
|
|
1474
1474
|
{"key":"L0102","section":"Progress","text":"Progress","placement":"unplaced","state":"standing"},
|
|
1475
|
-
{"key":"L0103","section":"Progress","text":"How your output has changed over time — work shipped, cost and time per work, and how reviews held up.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1475
|
+
{"key":"L0103","section":"Progress","text":"How your output has changed over time — work shipped, cost and time per work, and how reviews held up.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":182,"string_id":"298ff22576ee","state":"standing"},
|
|
1476
1476
|
{"key":"L0104","section":"Progress","text":"You","placement":"placed","file":"modules/hall-ui/public/board-room.js","line":440,"string_id":"8e527ab12334","state":"standing","occurrences":3},
|
|
1477
1477
|
{"key":"L0105","section":"Progress","text":"All builders","placement":"placed","file":"modules/hall-ui/public/hall-render.js","line":1180,"string_id":"8b736e365191","state":"standing","occurrences":3},
|
|
1478
1478
|
{"key":"L0106","section":"Progress","text":"Kind of work","placement":"placed","file":"modules/hall-ui/public/hall-render.js","line":1145,"string_id":"e3b473af2f69","state":"standing"},
|
|
@@ -1497,7 +1497,7 @@
|
|
|
1497
1497
|
{"key":"L0125","section":"Progress","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","state":"standing"},
|
|
1498
1498
|
{"key":"L0126","section":"Progress","text":"Kinds of work shipped","placement":"placed","file":"modules/hall-ui/public/hall-render.js","line":1258,"string_id":"7d6eaa8d4514","state":"standing"},
|
|
1499
1499
|
{"key":"L0127","section":"Achievements","text":"Achievements","placement":"unplaced","state":"standing"},
|
|
1500
|
-
{"key":"L0128","section":"Achievements","text":"Eight achievements recognize sustained contribution. Earned ones are highlighted; the rest show what’s left to do.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
1500
|
+
{"key":"L0128","section":"Achievements","text":"Eight achievements recognize sustained contribution. Earned ones are highlighted; the rest show what’s left to do.","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":197,"string_id":"854a21d2eb39","state":"standing"},
|
|
1501
1501
|
{"key":"L0129","section":"Achievements","text":"Won {…}","placement":"placed","file":"modules/hall-ui/public/builders.js","line":477,"string_id":"c5fd76a9e03d","state":"standing","occurrences":6},
|
|
1502
1502
|
{"key":"L0130","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":467,"string_id":"1883ad7f07fc","state":"standing","occurrences":2},
|
|
1503
1503
|
{"key":"L0131","section":"Next up — ready to claim","text":"Next up — ready to claim","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":103,"string_id":"659d8256139c"},
|
|
@@ -2180,7 +2180,7 @@
|
|
|
2180
2180
|
"surface": "builders",
|
|
2181
2181
|
"title": "Profile",
|
|
2182
2182
|
"states_read": ["own","works","activity","other","out"],
|
|
2183
|
-
"files_hash": "
|
|
2183
|
+
"files_hash": "a49addd2cc436a47",
|
|
2184
2184
|
"reading_hash": "c97a395a2b823405",
|
|
2185
2185
|
"counts": {"lines":115,"placed":48,"shared":5,"unplaced":62},
|
|
2186
2186
|
"omitted": {"data":172},
|
|
@@ -2221,7 +2221,7 @@
|
|
|
2221
2221
|
{"key":"L0033","section":"Goals created","text":"Goal","placement":"placed","file":"modules/hall-ui/public/gate.js","line":288,"string_id":"ec88b946ad16","state":"activity"},
|
|
2222
2222
|
{"key":"L0034","section":"Goals created","text":"Roles","placement":"unplaced","state":"activity"},
|
|
2223
2223
|
{"key":"L0035","section":"Goals created","text":"Progress","placement":"unplaced","state":"activity"},
|
|
2224
|
-
{"key":"L0036","section":"Goals created","text":"{…} of {…} shipped","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2224
|
+
{"key":"L0036","section":"Goals created","text":"{…} of {…} shipped","placement":"placed","file":"modules/hall-ui/public/profile.js","line":595,"string_id":"c3d9687e2375","state":"activity","occurrences":2},
|
|
2225
2225
|
{"key":"L0037","section":"Goals created","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","state":"activity"},
|
|
2226
2226
|
{"key":"L0038","section":"Ideas filed, and what became of them","text":"Ideas filed, and what became of them","placement":"placed","file":"modules/hall-ui/public/profile.html","line":152,"string_id":"d4e21769ce1c","state":"activity"},
|
|
2227
2227
|
{"key":"L0039","section":"Ideas filed, and what became of them","text":"Every idea this builder captured — promoted, discarded, merged, or still open.","placement":"placed","file":"modules/hall-ui/public/profile.html","line":153,"string_id":"8825f1d90dd1","state":"activity"},
|
|
@@ -2238,12 +2238,12 @@
|
|
|
2238
2238
|
{"key":"L0050","section":"Ideas filed, and what became of them","text":"Became 2 {…}","placement":"unplaced","state":"activity","occurrences":2},
|
|
2239
2239
|
{"key":"L0051","section":"Ideas filed, and what became of them","text":"Then caused 1 task","placement":"unplaced","state":"activity","occurrences":2},
|
|
2240
2240
|
{"key":"L0052","section":"Ideas filed, and what became of them","text":"Earned 96 {…} so far","placement":"unplaced","state":"activity"},
|
|
2241
|
-
{"key":"L0053","section":"Ideas filed, and what became of them","text":"Still open","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2242
|
-
{"key":"L0054","section":"Ideas filed, and what became of them","text":"Merged into","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2241
|
+
{"key":"L0053","section":"Ideas filed, and what became of them","text":"Still open","placement":"placed","file":"modules/hall-ui/public/profile.js","line":494,"string_id":"efe530c0e3a7","state":"activity"},
|
|
2242
|
+
{"key":"L0054","section":"Ideas filed, and what became of them","text":"Merged into","placement":"placed","file":"modules/hall-ui/public/profile.js","line":489,"string_id":"c7a670e9552d","state":"activity"},
|
|
2243
2243
|
{"key":"L0055","section":"Ideas filed, and what became of them","text":"Earned 12 {…} so far","placement":"unplaced","state":"activity"},
|
|
2244
2244
|
{"key":"L0056","section":"Ideas filed, and what became of them","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","state":"activity","occurrences":2},
|
|
2245
2245
|
{"key":"L0057","section":"Ideas filed, and what became of them","text":"Earned 180 {…} so far","placement":"unplaced","state":"activity"},
|
|
2246
|
-
{"key":"L0058","section":"Ideas filed, and what became of them","text":"{…} of {…} shipped","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2246
|
+
{"key":"L0058","section":"Ideas filed, and what became of them","text":"{…} of {…} shipped","placement":"placed","file":"modules/hall-ui/public/profile.js","line":595,"string_id":"c3d9687e2375","state":"activity"},
|
|
2247
2247
|
{"key":"L0059","section":"Ideas filed, and what became of them","text":"Discarded","placement":"unplaced","state":"activity"},
|
|
2248
2248
|
{"key":"L0060","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":467,"string_id":"1883ad7f07fc","state":"activity","occurrences":3},
|
|
2249
2249
|
{"key":"L0061","section":"Works","text":"Works","placement":"unplaced","state":"works"},
|
|
@@ -2268,7 +2268,7 @@
|
|
|
2268
2268
|
{"key":"L0080","section":"Over time","text":"30 days","placement":"unplaced"},
|
|
2269
2269
|
{"key":"L0081","section":"Over time","text":"90 days","placement":"unplaced"},
|
|
2270
2270
|
{"key":"L0082","section":"Over time","text":"1 year","placement":"unplaced"},
|
|
2271
|
-
{"key":"L0083","section":"Over time","text":"All time","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":
|
|
2271
|
+
{"key":"L0083","section":"Over time","text":"All time","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":130,"string_id":"627c683a5e5d"},
|
|
2272
2272
|
{"key":"L0084","section":"Over time","text":"Works {…}","placement":"unplaced"},
|
|
2273
2273
|
{"key":"L0085","section":"Over time","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","occurrences":3},
|
|
2274
2274
|
{"key":"L0086","section":"Over time","text":"24 works","placement":"unplaced"},
|
|
@@ -2287,7 +2287,7 @@
|
|
|
2287
2287
|
{"key":"L0099","section":"Over time","text":"this week","placement":"unplaced"},
|
|
2288
2288
|
{"key":"L0100","section":"Over time","text":"61 in the last 90 days · only you see this one","placement":"unplaced"},
|
|
2289
2289
|
{"key":"L0101","section":"Achievements","text":"Achievements","placement":"unplaced"},
|
|
2290
|
-
{"key":"L0102","section":"Achievements","text":"Won {…}","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2290
|
+
{"key":"L0102","section":"Achievements","text":"Won {…}","placement":"placed","file":"modules/hall-ui/public/profile.js","line":151,"string_id":"c5fd76a9e03d","occurrences":2},
|
|
2291
2291
|
{"key":"L0103","section":"Cross-project record","text":"Cross-project record","placement":"placed","file":"modules/hall-ui/public/profile.html","line":94,"string_id":"a55e423263f0"},
|
|
2292
2292
|
{"key":"L0104","section":"Cross-project record","text":"Projects","placement":"unplaced"},
|
|
2293
2293
|
{"key":"L0105","section":"Cross-project record","text":"Works {…}","placement":"unplaced"},
|
|
@@ -2295,12 +2295,12 @@
|
|
|
2295
2295
|
{"key":"L0107","section":"Cross-project record","text":"Karma","placement":"unplaced"},
|
|
2296
2296
|
{"key":"L0108","section":"Cross-project record","text":"Roles: {…}, UI · Last {…} {…}","placement":"unplaced"},
|
|
2297
2297
|
{"key":"L0109","section":"Cross-project record","text":"Project","placement":"unplaced"},
|
|
2298
|
-
{"key":"L0110","section":"Cross-project record","text":"Standing there","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2298
|
+
{"key":"L0110","section":"Cross-project record","text":"Standing there","placement":"placed","file":"modules/hall-ui/public/profile.js","line":314,"string_id":"ec1c2dae4a90"},
|
|
2299
2299
|
{"key":"L0111","section":"Cross-project record","text":"Archon","placement":"unplaced"},
|
|
2300
2300
|
{"key":"L0112","section":"Cross-project record","text":"Metic","placement":"unplaced"},
|
|
2301
|
-
{"key":"L0113","section":"Cross-project record","text":"+ {…} more project{…} not publicly listed.","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2302
|
-
{"key":"L0114","section":"Cross-project record","text":"This is you —","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2303
|
-
{"key":"L0115","section":"Cross-project record","text":"manage its visibility in Settings → Profile and privacy","placement":"placed","file":"modules/hall-ui/public/profile.js","line":
|
|
2301
|
+
{"key":"L0113","section":"Cross-project record","text":"+ {…} more project{…} not publicly listed.","placement":"placed","file":"modules/hall-ui/public/profile.js","line":320,"string_id":"646fab1157fe"},
|
|
2302
|
+
{"key":"L0114","section":"Cross-project record","text":"This is you —","placement":"placed","file":"modules/hall-ui/public/profile.js","line":290,"string_id":"23f531302e9e"},
|
|
2303
|
+
{"key":"L0115","section":"Cross-project record","text":"manage its visibility in Settings → Profile and privacy","placement":"placed","file":"modules/hall-ui/public/profile.js","line":290,"string_id":"bc7923324b96"}
|
|
2304
2304
|
]
|
|
2305
2305
|
},
|
|
2306
2306
|
{
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- core_268 — a builder's MAIN role, chosen by the builder (task 1004433 /
|
|
2
|
+
-- WA6.RP03, goal 1000095, criterion wa6-roles-read-true-in-public)
|
|
3
|
+
--
|
|
4
|
+
-- The owner's 2026-09-30 decision on the role-shaped profile (task 1004431, the
|
|
5
|
+
-- approved mock docs/design/mocks/profile-roles/): one person has one profile,
|
|
6
|
+
-- each builder chooses their own MAIN role, and it leads their header, their
|
|
7
|
+
-- chips and their leaderboard column.
|
|
8
|
+
--
|
|
9
|
+
-- preferred_disciplines (027 + 086) cannot carry it. It is a set, and
|
|
10
|
+
-- updateBuilderDisciplines stores it in the CANONICAL order of the enabled
|
|
11
|
+
-- disciplines whatever order the builder picked, so its first element is the
|
|
12
|
+
-- alphabet's choice, not theirs. A separate nullable column says the one thing
|
|
13
|
+
-- the set cannot: which of them the builder put first.
|
|
14
|
+
--
|
|
15
|
+
-- NULL means "not chosen", and is a real answer: the profile then falls back to
|
|
16
|
+
-- the craft the builder has earned most in, and says the role was inferred. No
|
|
17
|
+
-- backfill, because nobody has chosen yet and inventing a choice for them is the
|
|
18
|
+
-- thing the column exists not to do.
|
|
19
|
+
--
|
|
20
|
+
-- No CHECK on the value. The discipline vocabulary is open (a module may
|
|
21
|
+
-- contribute one, ADR 0272), so the route validates against the enabled set and
|
|
22
|
+
-- against the builder's own preferred set, the same way preferred_disciplines
|
|
23
|
+
-- itself is validated since 086 dropped its CHECK.
|
|
24
|
+
--
|
|
25
|
+
-- Additive and idempotent: one nullable column, no default, no data. An older
|
|
26
|
+
-- release running against it never reads the column. Rollback is DROP COLUMN.
|
|
27
|
+
|
|
28
|
+
ALTER TABLE builders
|
|
29
|
+
ADD COLUMN IF NOT EXISTS main_discipline text;
|
|
30
|
+
|
|
31
|
+
COMMENT ON COLUMN builders.main_discipline IS
|
|
32
|
+
'The builder''s own choice of MAIN role (task 1004433). NULL = not chosen; the profile then infers it from credits earned. Always one of preferred_disciplines when set (enforced in updateBuilderDisciplines).';
|
|
33
|
+
|
|
34
|
+
INSERT INTO schema_migrations (version) VALUES ('core_268_builders_main_discipline')
|
|
35
|
+
ON CONFLICT DO NOTHING;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// modules/copy-desk/artist-stats.js — the artist's LEDGER READS: the studio
|
|
2
|
+
// corner's credit rows, and the profile's artist numbers (task 1004433 /
|
|
3
|
+
// WA6.RP03). Apart from routes/copy-desk.js because that file is at the
|
|
4
|
+
// 1,500-line ratchet (the page-decisions.js precedent); the route requires
|
|
5
|
+
// `tallyCreditRows` from here for GET /copy-desk/tally, so the studio and the
|
|
6
|
+
// profile read the same rows through the same call.
|
|
7
|
+
//
|
|
8
|
+
// Reads only. Nothing here writes, and nothing here returns a word of copy:
|
|
9
|
+
// counts, sums and surface labels. That is what lets `copy-desk.artistStats` be
|
|
10
|
+
// the one port this module provides without opening a copy write path
|
|
11
|
+
// (tests/copy_no_cms.mjs pins exactly this one).
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const api = require('../../src/module-api');
|
|
16
|
+
const pageData = require('./page-data');
|
|
17
|
+
const pageStatus = require('./page-status');
|
|
18
|
+
|
|
19
|
+
// Every `tweak.page_approved:` credit row the builder has, through the reward
|
|
20
|
+
// port (credit_log is economy's table). No reward port, or no approved page
|
|
21
|
+
// landed yet (economy books one row per landed round, task 1004324), reads as
|
|
22
|
+
// none: a tally of 0 is the truth then.
|
|
23
|
+
//
|
|
24
|
+
// ONE bounded query. An approved page books one row, so the cap is thousands of
|
|
25
|
+
// pages for one artist; past it the tally says `truncated` (creditLedger's
|
|
26
|
+
// `total` is the unpaginated count) rather than paging in a loop.
|
|
27
|
+
const TALLY_ROW_CAP = 5000;
|
|
28
|
+
async function tallyCreditRows(builderId) {
|
|
29
|
+
const reward = api.resolveOptional && api.resolveOptional('reward');
|
|
30
|
+
if (!reward || typeof reward.creditLedger !== 'function') return { rows: [], truncated: false };
|
|
31
|
+
const { rows, total } = await reward.creditLedger(builderId, { reasonPrefix: pageStatus.TALLY_REASON_PREFIX, limit: TALLY_ROW_CAP });
|
|
32
|
+
const list = rows || [];
|
|
33
|
+
return { rows: list, truncated: Number(total) > list.length };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The profile's artist numbers, for core's profile route through the
|
|
37
|
+
// `copy-desk.artistStats` port: the SAME reads the studio's tally and page list
|
|
38
|
+
// make, composed by page-status.js composeArtistStats. No lifecycle port reads
|
|
39
|
+
// as null (could not ask), never as zero. A missing page inventory leaves the
|
|
40
|
+
// per-surface lines empty and keeps the tally, which comes from the ledger.
|
|
41
|
+
async function readArtistStats(builderId, { now = new Date() } = {}) {
|
|
42
|
+
const lifecycle = api.resolveOptional && api.resolveOptional('lifecycle');
|
|
43
|
+
if (!lifecycle || typeof lifecycle.listPageTweakTasks !== 'function') return null;
|
|
44
|
+
const inv = pageData.loadInventory();
|
|
45
|
+
// Only this artist's rounds, read from their own web claims: a public page
|
|
46
|
+
// must not cost a scan of every round the project has ever had.
|
|
47
|
+
const [tasks, credit] = await Promise.all([lifecycle.listPageTweakTasks({ artistId: builderId }), tallyCreditRows(builderId)]);
|
|
48
|
+
const out = pageStatus.composeArtistStats({
|
|
49
|
+
builderId, inventory: inv.ok ? inv.data : null, tasks, creditRows: credit.rows, now,
|
|
50
|
+
});
|
|
51
|
+
out.inventory_known = !!inv.ok;
|
|
52
|
+
out.truncated = credit.truncated;
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { tallyCreditRows, readArtistStats, TALLY_ROW_CAP };
|
|
@@ -347,6 +347,44 @@ function composeTally({ builderId, tasks, creditRows, now }) {
|
|
|
347
347
|
};
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
// The profile's ARTIST numbers (task 1004433 / WA6.RP03; the mock is
|
|
351
|
+
// docs/design/mocks/profile-roles/): the corner tally above, unchanged, plus
|
|
352
|
+
// "N of M tweaked" per surface for THIS artist. The studio's per-surface line
|
|
353
|
+
// (composePages) counts every artist's rounds; a profile is one person's record,
|
|
354
|
+
// so a page counts here when it has a shipped round whose artist is them. M is
|
|
355
|
+
// the surface's whole page count, the same denominator the studio shows.
|
|
356
|
+
//
|
|
357
|
+
// `pages_approved` is the tally's own count of approved ROUNDS (each one paid);
|
|
358
|
+
// `pages` is how many DISTINCT pages those rounds touched, the sum of the
|
|
359
|
+
// per-surface N. The two differ once an artist tweaks the same page twice.
|
|
360
|
+
//
|
|
361
|
+
// Counts and sums only: no wording, no page title beyond the surface's label,
|
|
362
|
+
// because the owner's decision (a) keeps these numbers public and the pages
|
|
363
|
+
// themselves behind a sign-in.
|
|
364
|
+
function composeArtistStats({ builderId, inventory, tasks, creditRows, now }) {
|
|
365
|
+
const tally = composeTally({ builderId, tasks, creditRows, now });
|
|
366
|
+
const byPage = indexRounds(tasks);
|
|
367
|
+
const mine = new Set();
|
|
368
|
+
for (const [pageId, rounds] of byPage) {
|
|
369
|
+
if (rounds.some((r) => r.status === 'shipped' && String(r.artist_id) === String(builderId))) mine.add(pageId);
|
|
370
|
+
}
|
|
371
|
+
const all = (inventory && inventory.pages) || [];
|
|
372
|
+
const surfaces = orderedSurfaces(inventory).map((id) => {
|
|
373
|
+
const on = all.filter((p) => p && p.surface === id);
|
|
374
|
+
const tweaked = on.filter((p) => mine.has(p.id)).length;
|
|
375
|
+
return { id, label: SURFACE_LABELS[id] || id, tweaked, total: on.length, line: `${tweaked} of ${on.length} tweaked` };
|
|
376
|
+
});
|
|
377
|
+
return {
|
|
378
|
+
pages_approved: tally.pages_tweaked,
|
|
379
|
+
pages: surfaces.reduce((n, s) => n + s.tweaked, 0),
|
|
380
|
+
surfaces_touched: surfaces.filter((s) => s.tweaked > 0).length,
|
|
381
|
+
credits: tally.credits,
|
|
382
|
+
this_week: tally.this_week,
|
|
383
|
+
week_since: tally.week_since,
|
|
384
|
+
surfaces,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
350
388
|
// ---------------------------------------------------------------------------
|
|
351
389
|
// The recommendation, "what should I tweak next" (task 1004318 / BV2.TW07,
|
|
352
390
|
// ADR 0341 D8). The fourth read, over the same ledger rows as the other three
|
|
@@ -689,4 +727,5 @@ module.exports = {
|
|
|
689
727
|
composePage,
|
|
690
728
|
lastRoundShippedAt,
|
|
691
729
|
composeTally,
|
|
730
|
+
composeArtistStats,
|
|
692
731
|
};
|
|
@@ -62,6 +62,7 @@ const pageStatus = require('../page-status');
|
|
|
62
62
|
const pages = require('../pages');
|
|
63
63
|
const docx = require('../docx');
|
|
64
64
|
const { waitingRoundOrFail, refuseDecision, nextWaiting } = require('../page-decisions');
|
|
65
|
+
const { tallyCreditRows, readArtistStats } = require('../artist-stats');
|
|
65
66
|
|
|
66
67
|
const { validateOrRespond } = api;
|
|
67
68
|
|
|
@@ -360,26 +361,16 @@ function pageReadsOrFail(res) {
|
|
|
360
361
|
return lifecycle;
|
|
361
362
|
}
|
|
362
363
|
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
// landed yet (economy books one row per landed round, task 1004324), reads as
|
|
366
|
-
// none: a tally of 0 is the truth then.
|
|
367
|
-
//
|
|
368
|
-
// ONE bounded query. An approved page books one row, so the cap is thousands of
|
|
369
|
-
// pages for one artist; past it the tally says `truncated` (creditLedger's
|
|
370
|
-
// `total` is the unpaginated count) rather than paging in a loop.
|
|
371
|
-
const TALLY_ROW_CAP = 5000;
|
|
372
|
-
async function tallyCreditRows(builderId) {
|
|
373
|
-
const reward = api.resolveOptional && api.resolveOptional('reward');
|
|
374
|
-
if (!reward || typeof reward.creditLedger !== 'function') return { rows: [], truncated: false };
|
|
375
|
-
const { rows, total } = await reward.creditLedger(builderId, { reasonPrefix: pageStatus.TALLY_REASON_PREFIX, limit: TALLY_ROW_CAP });
|
|
376
|
-
const list = rows || [];
|
|
377
|
-
return { rows: list, truncated: Number(total) > list.length };
|
|
378
|
-
}
|
|
364
|
+
// The tally's credit rows and the profile's artist numbers live in
|
|
365
|
+
// ../artist-stats.js (task 1004433); this file is at the 1,500-line ratchet.
|
|
379
366
|
|
|
380
367
|
module.exports = function buildCopyDeskRouter() {
|
|
381
368
|
const router = express.Router();
|
|
382
369
|
|
|
370
|
+
if (!api.hasProvider('copy-desk.artistStats')) {
|
|
371
|
+
api.registerProvider('copy-desk.artistStats', readArtistStats);
|
|
372
|
+
}
|
|
373
|
+
|
|
383
374
|
// Page asks resolve when the page's tweak ships (ADR 0341 D6). Re-registered
|
|
384
375
|
// on every router build (tests rebuild it), never stacked.
|
|
385
376
|
if (_askListenerOff) _askListenerOff();
|
|
@@ -287,7 +287,16 @@ await test('the Approval queue decides only through the port, and a send-back wr
|
|
|
287
287
|
|
|
288
288
|
await test('the module manifest declares no seam another module could write copy through', () => {
|
|
289
289
|
const manifest = JSON.parse(read('module.json'));
|
|
290
|
-
|
|
290
|
+
// ONE port, and it is a read of counts (task 1004433 / WA6.RP03): the
|
|
291
|
+
// profile's artist numbers. Anything more provided here would be a seam
|
|
292
|
+
// another module could reach copy through, so the list is pinned exactly and
|
|
293
|
+
// the provider is held to returning no wording below.
|
|
294
|
+
assert.deepEqual(manifest.provides, ['copy-desk.artistStats'], 'a provided port here would be a copy write path for every other module');
|
|
295
|
+
const stats = read('artist-stats.js');
|
|
296
|
+
assert.equal(/\b(pool|query|writeFile|appendFile|INSERT|UPDATE|DELETE)\b/.test(stats.replace(/\/\/.*$/gm, '')), false,
|
|
297
|
+
'the artist-stats port reads through other ports and writes nothing');
|
|
298
|
+
assert.equal(/\b(lines|before|after|reading|description|title)\s*:/.test(stats.replace(/\/\/.*$/gm, '')), false,
|
|
299
|
+
'the artist-stats port returns counts and sums, never wording');
|
|
291
300
|
// R03 consumes `lifecycle` to create the proposal task. That direction is the
|
|
292
301
|
// safe one and the point: this module can put a work request INTO the ledger,
|
|
293
302
|
// and nothing can pull copy OUT of this module.
|