@bongos/core 1.21.170 → 1.21.171
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 +19 -19
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-readings.json +15 -15
- package/modules/hall-ui/public/brand-apply.js +13 -6
- package/modules/hall-ui/public/sky-data.js +5 -4
- package/modules/hall-ui/public/sky-panel.js +1 -1
- package/modules/lifecycle/sky.js +8 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/module-api.js +1 -1
- package/tests/goal_map_page.mjs +5 -5
- package/tests/hall_sky.mjs +16 -4
- package/tests/reward_mode_surfacing.mjs +16 -3
- package/tests/sky_read.mjs +13 -2
package/.bongos-core.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.21.
|
|
6
|
-
"core_contract": "1.21.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.21.171",
|
|
6
|
+
"core_contract": "1.21.171",
|
|
7
|
+
"source_commit": "418b7346b2799fc4dabcb37cdec6ee5e35bfe89d",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-10-23T17:
|
|
9
|
+
"built_at": "2026-10-23T17:36:25.226Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 609,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 3831,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "5c91b3622476a3b85881740bd79ae9654ed7c2580f183150aa266e127b023ede",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2927,7 +2927,7 @@
|
|
|
2927
2927
|
{
|
|
2928
2928
|
"path": "docs/module-api-changelog.md",
|
|
2929
2929
|
"mode": "0000644",
|
|
2930
|
-
"sha256": "
|
|
2930
|
+
"sha256": "681bd3bde29fddb39088d942d359acd61ebf692b57b2e1bdd46ab9317a25b80a"
|
|
2931
2931
|
},
|
|
2932
2932
|
{
|
|
2933
2933
|
"path": "docs/modules-contract.md",
|
|
@@ -3017,7 +3017,7 @@
|
|
|
3017
3017
|
{
|
|
3018
3018
|
"path": "docs/page-readings.json",
|
|
3019
3019
|
"mode": "0000644",
|
|
3020
|
-
"sha256": "
|
|
3020
|
+
"sha256": "57d09e6a2963858978e3028ddf8335d2712d1cad381264340fd51036cfade08c"
|
|
3021
3021
|
},
|
|
3022
3022
|
{
|
|
3023
3023
|
"path": "docs/project-context.template.md",
|
|
@@ -5627,7 +5627,7 @@
|
|
|
5627
5627
|
{
|
|
5628
5628
|
"path": "modules/hall-ui/public/brand-apply.js",
|
|
5629
5629
|
"mode": "0000644",
|
|
5630
|
-
"sha256": "
|
|
5630
|
+
"sha256": "311edb9f328f02ee1d30a3711a149f9e168dd7d3b7a83ab4403250653ef8a8fe"
|
|
5631
5631
|
},
|
|
5632
5632
|
{
|
|
5633
5633
|
"path": "modules/hall-ui/public/brand-holes.js",
|
|
@@ -6522,7 +6522,7 @@
|
|
|
6522
6522
|
{
|
|
6523
6523
|
"path": "modules/hall-ui/public/sky-data.js",
|
|
6524
6524
|
"mode": "0000644",
|
|
6525
|
-
"sha256": "
|
|
6525
|
+
"sha256": "a92f2804b755a0d4b3a28d4fdb9f8bc50e274cf04c4627b220f34c84a45a08ed"
|
|
6526
6526
|
},
|
|
6527
6527
|
{
|
|
6528
6528
|
"path": "modules/hall-ui/public/sky-draw.js",
|
|
@@ -6542,7 +6542,7 @@
|
|
|
6542
6542
|
{
|
|
6543
6543
|
"path": "modules/hall-ui/public/sky-panel.js",
|
|
6544
6544
|
"mode": "0000644",
|
|
6545
|
-
"sha256": "
|
|
6545
|
+
"sha256": "a34bc56a1ebe3c65282f9f2e1d36b1102eda4cbf5fc26192239281aec0bf8f81"
|
|
6546
6546
|
},
|
|
6547
6547
|
{
|
|
6548
6548
|
"path": "modules/hall-ui/public/sky-tour.js",
|
|
@@ -7807,7 +7807,7 @@
|
|
|
7807
7807
|
{
|
|
7808
7808
|
"path": "modules/lifecycle/sky.js",
|
|
7809
7809
|
"mode": "0000644",
|
|
7810
|
-
"sha256": "
|
|
7810
|
+
"sha256": "98011414e3e393667766a499bc8a7ad3f145d2c42563dca9ff6f35b8c4da16a2"
|
|
7811
7811
|
},
|
|
7812
7812
|
{
|
|
7813
7813
|
"path": "modules/lifecycle/task-classifier.js",
|
|
@@ -10602,12 +10602,12 @@
|
|
|
10602
10602
|
{
|
|
10603
10603
|
"path": "package-lock.json",
|
|
10604
10604
|
"mode": "0000644",
|
|
10605
|
-
"sha256": "
|
|
10605
|
+
"sha256": "829b2b61f5ea654c0e6b28e1a8afb189f1c0144277a36d1296a0d8adab46667b"
|
|
10606
10606
|
},
|
|
10607
10607
|
{
|
|
10608
10608
|
"path": "package.json",
|
|
10609
10609
|
"mode": "0000644",
|
|
10610
|
-
"sha256": "
|
|
10610
|
+
"sha256": "ddc6efda55ff0a4c999375dd67b7018f906d14104d932d745d607d9b43df9ff4"
|
|
10611
10611
|
},
|
|
10612
10612
|
{
|
|
10613
10613
|
"path": "public-docs/index.html",
|
|
@@ -10627,7 +10627,7 @@
|
|
|
10627
10627
|
{
|
|
10628
10628
|
"path": "release-notes.json",
|
|
10629
10629
|
"mode": "0000644",
|
|
10630
|
-
"sha256": "
|
|
10630
|
+
"sha256": "f91ffba352e1b52333a16db4f2468e2f32ae7372a14292175b66272f5731dbd2"
|
|
10631
10631
|
},
|
|
10632
10632
|
{
|
|
10633
10633
|
"path": "scripts/cron/style_guide_audit.sh",
|
|
@@ -13017,7 +13017,7 @@
|
|
|
13017
13017
|
{
|
|
13018
13018
|
"path": "src/module-api.js",
|
|
13019
13019
|
"mode": "0000644",
|
|
13020
|
-
"sha256": "
|
|
13020
|
+
"sha256": "12e9bdeef58e00243274a7711fc7a93f21c838698dafeb8a3b7680a572271bfd"
|
|
13021
13021
|
},
|
|
13022
13022
|
{
|
|
13023
13023
|
"path": "src/module-loader/catalog.js",
|
|
@@ -14917,7 +14917,7 @@
|
|
|
14917
14917
|
{
|
|
14918
14918
|
"path": "tests/goal_map_page.mjs",
|
|
14919
14919
|
"mode": "0000644",
|
|
14920
|
-
"sha256": "
|
|
14920
|
+
"sha256": "aa83961201bf3ff0757330b16a799b4de407d0cc2522282f18712dbf624a84ea"
|
|
14921
14921
|
},
|
|
14922
14922
|
{
|
|
14923
14923
|
"path": "tests/goal_member_kinds.mjs",
|
|
@@ -15732,7 +15732,7 @@
|
|
|
15732
15732
|
{
|
|
15733
15733
|
"path": "tests/hall_sky.mjs",
|
|
15734
15734
|
"mode": "0000644",
|
|
15735
|
-
"sha256": "
|
|
15735
|
+
"sha256": "f798b71ce6f21026afc89bbca1e35fca06919d38f56eca1f8d8cfc75b3e9ac85"
|
|
15736
15736
|
},
|
|
15737
15737
|
{
|
|
15738
15738
|
"path": "tests/hall_states_regex_escapes.mjs",
|
|
@@ -17887,7 +17887,7 @@
|
|
|
17887
17887
|
{
|
|
17888
17888
|
"path": "tests/reward_mode_surfacing.mjs",
|
|
17889
17889
|
"mode": "0000644",
|
|
17890
|
-
"sha256": "
|
|
17890
|
+
"sha256": "9d8e28d50abfb2b0e339f7b934a1ae230812340739bcdc13e4550f7e99d8659b"
|
|
17891
17891
|
},
|
|
17892
17892
|
{
|
|
17893
17893
|
"path": "tests/role_responsibilities.mjs",
|
|
@@ -18462,7 +18462,7 @@
|
|
|
18462
18462
|
{
|
|
18463
18463
|
"path": "tests/sky_read.mjs",
|
|
18464
18464
|
"mode": "0000644",
|
|
18465
|
-
"sha256": "
|
|
18465
|
+
"sha256": "238538864553803ed21a6330bf5a3570d1da8bd2f691af45b9eec1773a3bd8cd"
|
|
18466
18466
|
},
|
|
18467
18467
|
{
|
|
18468
18468
|
"path": "tests/smoke_dependencies_witness.mjs",
|
|
@@ -3177,5 +3177,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
3177
3177
|
landed since 1.21.168 with no explicit bump. run 39992064615. (task 1002620)
|
|
3178
3178
|
1.21.170 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3179
3179
|
landed since 1.21.169 with no explicit bump. run 39994339257. (task 1002620)
|
|
3180
|
+
1.21.171 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3181
|
+
landed since 1.21.170 with no explicit bump. run 39996371081. (task 1002620)
|
|
3180
3182
|
---------------------------------------------------------------------------
|
|
3181
3183
|
```
|
package/docs/page-readings.json
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"surface": "builders",
|
|
51
51
|
"title": "Blockers",
|
|
52
52
|
"states_read": ["default"],
|
|
53
|
-
"files_hash": "
|
|
53
|
+
"files_hash": "f5bf3c2244e3fbdd",
|
|
54
54
|
"reading_hash": "2b3fd98b7ba1bff6",
|
|
55
55
|
"counts": {"lines":28,"placed":12,"shared":8,"unplaced":8},
|
|
56
56
|
"omitted": {"data":9},
|
|
@@ -1141,7 +1141,7 @@
|
|
|
1141
1141
|
"surface": "builders",
|
|
1142
1142
|
"title": "The sky",
|
|
1143
1143
|
"states_read": ["tour","sky","wells","ledger","full","full-back","out"],
|
|
1144
|
-
"files_hash": "
|
|
1144
|
+
"files_hash": "5f2c2f22c2fc9dc6",
|
|
1145
1145
|
"reading_hash": "b83eb8c92a23fd3c",
|
|
1146
1146
|
"counts": {"lines":47,"placed":23,"shared":7,"unplaced":17},
|
|
1147
1147
|
"omitted": {"data":8},
|
|
@@ -1201,7 +1201,7 @@
|
|
|
1201
1201
|
"surface": "builders",
|
|
1202
1202
|
"title": "Goals",
|
|
1203
1203
|
"states_read": ["list","filters","cards","detail","dependencies","out","uat","uat-panel","author"],
|
|
1204
|
-
"files_hash": "
|
|
1204
|
+
"files_hash": "4f6f4eb5e9f00412",
|
|
1205
1205
|
"reading_hash": "7aa1a6e1946dc077",
|
|
1206
1206
|
"counts": {"lines":156,"placed":52,"shared":8,"unplaced":96},
|
|
1207
1207
|
"omitted": {"data":268},
|
|
@@ -1326,7 +1326,7 @@
|
|
|
1326
1326
|
{"key":"L0117","section":"Goals","text":"Version","placement":"unplaced"},
|
|
1327
1327
|
{"key":"L0118","section":"Goals","text":"— any —","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":173,"string_id":"729d4ce22b99","occurrences":2},
|
|
1328
1328
|
{"key":"L0119","section":"Goals","text":"Status","placement":"unplaced"},
|
|
1329
|
-
{"key":"L0120","section":"Goals","text":"open","placement":"placed","file":"modules/hall-ui/public/approval-queue.js","line":
|
|
1329
|
+
{"key":"L0120","section":"Goals","text":"open","placement":"placed","file":"modules/hall-ui/public/approval-queue.js","line":166,"string_id":"9a803563c948","occurrences":16},
|
|
1330
1330
|
{"key":"L0121","section":"Goals","text":"Sort","placement":"unplaced"},
|
|
1331
1331
|
{"key":"L0122","section":"Goals","text":"priority (version order)","placement":"unplaced"},
|
|
1332
1332
|
{"key":"L0123","section":"Goals","text":"newest first","placement":"unplaced"},
|
|
@@ -1439,7 +1439,7 @@
|
|
|
1439
1439
|
"surface": "builders",
|
|
1440
1440
|
"title": "Builders' Hall",
|
|
1441
1441
|
"states_read": ["home","standing","standing-karma","out","founding","genesis","decide","demo"],
|
|
1442
|
-
"files_hash": "
|
|
1442
|
+
"files_hash": "e32eb071e46bec38",
|
|
1443
1443
|
"reading_hash": "42dbab4f3948fe66",
|
|
1444
1444
|
"counts": {"lines":117,"placed":63,"shared":10,"unplaced":44},
|
|
1445
1445
|
"omitted": {"data":101},
|
|
@@ -1569,7 +1569,7 @@
|
|
|
1569
1569
|
"surface": "builders",
|
|
1570
1570
|
"title": "Idea",
|
|
1571
1571
|
"states_read": ["record","missing"],
|
|
1572
|
-
"files_hash": "
|
|
1572
|
+
"files_hash": "7456ea53572161d4",
|
|
1573
1573
|
"reading_hash": "c9f9a84ab844c704",
|
|
1574
1574
|
"counts": {"lines":52,"placed":23,"shared":9,"unplaced":20},
|
|
1575
1575
|
"omitted": {"data":18},
|
|
@@ -1609,7 +1609,7 @@
|
|
|
1609
1609
|
{"key":"L0032","section":"Everything that fell out of it","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","state":"missing"},
|
|
1610
1610
|
{"key":"L0033","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":520,"string_id":"1883ad7f07fc","state":"missing","occurrences":2},
|
|
1611
1611
|
{"key":"L0034","section":"Everything that fell out of it","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":674,"string_id":"fd1903586e8e","state":"missing"},
|
|
1612
|
-
{"key":"L0035","section":"12A changelog every builder can read","text":"open","placement":"placed","file":"modules/hall-ui/public/approval-queue.js","line":
|
|
1612
|
+
{"key":"L0035","section":"12A changelog every builder can read","text":"open","placement":"placed","file":"modules/hall-ui/public/approval-queue.js","line":166,"string_id":"9a803563c948"},
|
|
1613
1613
|
{"key":"L0036","section":"12A changelog every builder can read","text":"had the thought · {…}","placement":"unplaced"},
|
|
1614
1614
|
{"key":"L0037","section":"12A changelog every builder can read","text":"{…}/100 complete","placement":"placed","file":"modules/hall-ui/public/idea.js","line":87,"string_id":"c43050b62297"},
|
|
1615
1615
|
{"key":"L0038","section":"12A changelog every builder can read","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":4},
|
|
@@ -1719,7 +1719,7 @@
|
|
|
1719
1719
|
"surface": "builders",
|
|
1720
1720
|
"title": "Modules",
|
|
1721
1721
|
"states_read": ["browse","search-empty","lens","details","out"],
|
|
1722
|
-
"files_hash": "
|
|
1722
|
+
"files_hash": "6dc5460706966349",
|
|
1723
1723
|
"reading_hash": "a17f501b72321b7b",
|
|
1724
1724
|
"counts": {"lines":62,"placed":29,"shared":8,"unplaced":25},
|
|
1725
1725
|
"omitted": {"data":106},
|
|
@@ -2325,7 +2325,7 @@
|
|
|
2325
2325
|
"surface": "builders",
|
|
2326
2326
|
"title": "Profile",
|
|
2327
2327
|
"states_read": ["own","works","activity","activity-artist","activity-ideator","other","artist","ideator","out"],
|
|
2328
|
-
"files_hash": "
|
|
2328
|
+
"files_hash": "82a35b34a5115325",
|
|
2329
2329
|
"reading_hash": "8088d60a4e93bb91",
|
|
2330
2330
|
"counts": {"lines":196,"placed":70,"shared":8,"unplaced":118},
|
|
2331
2331
|
"omitted": {"data":197},
|
|
@@ -2721,7 +2721,7 @@
|
|
|
2721
2721
|
"surface": "builders",
|
|
2722
2722
|
"title": "Builders",
|
|
2723
2723
|
"states_read": ["roster","artists","search","out"],
|
|
2724
|
-
"files_hash": "
|
|
2724
|
+
"files_hash": "88e2f7aca1994346",
|
|
2725
2725
|
"reading_hash": "5c7e507e9600e59c",
|
|
2726
2726
|
"counts": {"lines":47,"placed":13,"shared":8,"unplaced":26},
|
|
2727
2727
|
"omitted": {"data":60},
|
|
@@ -2781,7 +2781,7 @@
|
|
|
2781
2781
|
"surface": "builders",
|
|
2782
2782
|
"title": "Sessions",
|
|
2783
2783
|
"states_read": ["ledger","out"],
|
|
2784
|
-
"files_hash": "
|
|
2784
|
+
"files_hash": "cd14ebd4d35e16bf",
|
|
2785
2785
|
"reading_hash": "5c18aaed7f2e8e0f",
|
|
2786
2786
|
"counts": {"lines":331,"placed":21,"shared":8,"unplaced":302},
|
|
2787
2787
|
"omitted": {"data":303},
|
|
@@ -4021,7 +4021,7 @@
|
|
|
4021
4021
|
"surface": "builders",
|
|
4022
4022
|
"title": "Task",
|
|
4023
4023
|
"states_read": ["record","from-goal","missing"],
|
|
4024
|
-
"files_hash": "
|
|
4024
|
+
"files_hash": "5535b9790b56985e",
|
|
4025
4025
|
"reading_hash": "3e80d092af1d7e2c",
|
|
4026
4026
|
"counts": {"lines":132,"placed":35,"shared":10,"unplaced":87},
|
|
4027
4027
|
"omitted": {"data":75},
|
|
@@ -4166,7 +4166,7 @@
|
|
|
4166
4166
|
"surface": "builders",
|
|
4167
4167
|
"title": "Your thinking",
|
|
4168
4168
|
"states_read": ["tour","sky","list","simple","full-idea","full","full-list","full-back","out"],
|
|
4169
|
-
"files_hash": "
|
|
4169
|
+
"files_hash": "a7b04635b758d676",
|
|
4170
4170
|
"reading_hash": "532805c03c3a8a4c",
|
|
4171
4171
|
"counts": {"lines":48,"placed":23,"shared":7,"unplaced":18},
|
|
4172
4172
|
"omitted": {"data":8},
|
|
@@ -4263,7 +4263,7 @@
|
|
|
4263
4263
|
"surface": "builders",
|
|
4264
4264
|
"title": "Watch",
|
|
4265
4265
|
"states_read": ["board","out","operations","security"],
|
|
4266
|
-
"files_hash": "
|
|
4266
|
+
"files_hash": "3980ad82a03bc297",
|
|
4267
4267
|
"reading_hash": "d698ac62c904aa65",
|
|
4268
4268
|
"counts": {"lines":88,"placed":38,"shared":8,"unplaced":42},
|
|
4269
4269
|
"omitted": {"data":166},
|
|
@@ -4364,7 +4364,7 @@
|
|
|
4364
4364
|
"surface": "builders",
|
|
4365
4365
|
"title": "Tasks",
|
|
4366
4366
|
"states_read": ["ready","in-progress","backlog","completed","filters-open","out","founding"],
|
|
4367
|
-
"files_hash": "
|
|
4367
|
+
"files_hash": "1dcb08711f496752",
|
|
4368
4368
|
"reading_hash": "a425c7a090d8bf03",
|
|
4369
4369
|
"counts": {"lines":125,"placed":54,"shared":8,"unplaced":63},
|
|
4370
4370
|
"omitted": {"data":316},
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
// estimate with a "<Currency> Est." label; settled → the actual ledger payout
|
|
92
92
|
// with a plain "<Currency>" label.
|
|
93
93
|
//
|
|
94
|
-
// task 1002469 — on a cost-plus-only instance that second case
|
|
94
|
+
// task 1002469 (superseded by task 1004781) — on a cost-plus-only instance that second case was a LIE. The
|
|
95
95
|
// per-task estimate is never paid, so credits_awarded is 0 on every shipped
|
|
96
96
|
// task, taskCreditValue's zero-fallback hands back the estimate, and the plain
|
|
97
97
|
// label then presents that estimate as the actual payout. So the "Est."
|
|
@@ -105,18 +105,25 @@
|
|
|
105
105
|
function taskCreditValue(task) {
|
|
106
106
|
if (!task) return null;
|
|
107
107
|
if (task.status === 'abandoned' || task.merged_into_task_id != null) return 0;
|
|
108
|
+
// task 1004781 — a settled task is worth what the ledger PAID for it and
|
|
109
|
+
// nothing else. It used to fall back to the estimate when the ledger held
|
|
110
|
+
// 0, and on a cost-plus-only instance that is every shipped task, so goal
|
|
111
|
+
// totals summed guesses as money (a goal read 3,373 for a builder paid
|
|
112
|
+
// 776). A settled 0 is the truth: the task itself paid nothing. Only
|
|
113
|
+
// unsettled work carries the estimate, and taskCreditLabel marks it "Est.".
|
|
114
|
+
// The decision the task asked for: estimates are KEPT, for live work only —
|
|
115
|
+
// they still rank claimable work (task-lib's best-value sort) and tell a
|
|
116
|
+
// builder roughly how big a task is — but they never reach a total.
|
|
108
117
|
if (taskSettled(task)) {
|
|
109
118
|
var awarded = Number(task.credits_awarded);
|
|
110
|
-
|
|
111
|
-
// ledger record (0 — legacy pre-ledger tasks, or reward-exempt), fall back
|
|
112
|
-
// to the estimate rather than showing a misleading "0".
|
|
113
|
-
if (isFinite(awarded) && awarded > 0) return awarded;
|
|
119
|
+
return isFinite(awarded) && awarded > 0 ? awarded : 0;
|
|
114
120
|
}
|
|
115
121
|
return task.credits_reward;
|
|
116
122
|
}
|
|
117
123
|
function taskCreditLabel(task, opts) {
|
|
124
|
+
// A settled figure is now always the actual payout (see taskCreditValue),
|
|
125
|
+
// so it takes the plain label on every reward mode; only an estimate is "Est.".
|
|
118
126
|
var base = currencyLabel(opts);
|
|
119
|
-
if (!perTaskCredit()) return base + ' Est.';
|
|
120
127
|
return taskSettled(task) ? base : base + ' Est.';
|
|
121
128
|
}
|
|
122
129
|
|
|
@@ -142,15 +142,16 @@
|
|
|
142
142
|
// The prototype read a snapshot (docs/design/mocks/sky/snapshot.js). Each
|
|
143
143
|
// adaptor maps one real read onto the same field names, so the world below
|
|
144
144
|
// is the prototype's world line for line.
|
|
145
|
+
const SETTLED = new Set(['confirmed', 'shipped']);
|
|
145
146
|
function goalFromSky(g) {
|
|
146
147
|
return {
|
|
147
148
|
id: String(g.goal_id), title: g.title || 'A private goal', subtitle: g.subtitle || null, version: g.version_id, status: g.status,
|
|
148
149
|
taskTotal: Number(g.task_total) || 0, taskDone: Number(g.task_done) || 0, createdAt: g.created_at || null,
|
|
149
150
|
crit: (g.criteria || []).map((c) => ({ id: String(c.id), text: c.criterion_md || '', satisfied: c.satisfied === true, tasks: (c.task_ids || []).map(String), pendingReview: c.pending_review === true, uat: c.uat_state || null, uatLabel: uatLabel(c.uat_state), backendOnly: c.backend_only === true })),
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
tasks: (g.tasks || []).map((t) => ({ id: String(t.id), title: t.title || 'a task', status: t.status, credits: t.status === 'abandoned' || t.credits_reward == null ?
|
|
151
|
+
// `credits` is what the ledger PAID — settled work only (task 1004781) — so a well's mass and a ring's weight are
|
|
152
|
+
// money paid. Live work carries its guess as `estimate`, shown "Est." and never added to a total. Abandoned (or
|
|
153
|
+
// merged-away, which is always abandoned — CHECK-constrained) work has neither (task 1004782).
|
|
154
|
+
tasks: (g.tasks || []).map((t) => ({ id: String(t.id), title: t.title || 'a task', status: t.status, credits: SETTLED.has(t.status) ? Number(t.credits_awarded) || 0 : 0, estimate: SETTLED.has(t.status) || t.status === 'abandoned' || t.credits_reward == null ? null : Number(t.credits_reward), createdAt: t.created_on || null, sourceRef: t.idea_id != null ? String(t.idea_id) : null })),
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
const taskRow = (t) => ({ id: String(t.task_id ?? t.id), title: t.title || 'a task', status: t.status, goalId: t.goal_id != null ? String(t.goal_id) : null, origin: t.origin || null });
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
<div class="facts">
|
|
99
99
|
${g ? fact('well', esc(g.title)) : ''}
|
|
100
100
|
${crit ? fact('gates the ring', esc(plain(crit.text).slice(0, 90))) : g ? fact('gates the ring', 'none — outer orbit') : ''}
|
|
101
|
-
${t.credits != null ? fact('credits', String(t.credits), true) : ''}
|
|
101
|
+
${t.estimate != null ? fact('credits', `${t.estimate} <span class="lbl">Est.</span>`, true) : t.credits != null ? fact('credits paid', String(t.credits), true) : ''}
|
|
102
102
|
${t.createdAt ? fact('born', esc(t.createdAt)) : ''}
|
|
103
103
|
${t.sourceRef ? fact('born of a thought', `<a href="${HALL}/idea/${esc(t.sourceRef)}" target="_blank" rel="noopener">${esc(ideaTitle(t.sourceRef))}</a>`) : ''}
|
|
104
104
|
</div>
|
package/modules/lifecycle/sky.js
CHANGED
|
@@ -44,6 +44,7 @@ const goalGraph = require('./goal-graph');
|
|
|
44
44
|
const goalCategory = require('./goal-category');
|
|
45
45
|
const { isPendingReview, uatState, uatReadColumnsSql } = require('./done-when');
|
|
46
46
|
const { TERMINAL_STATUSES } = require('./task-status');
|
|
47
|
+
const { CREDITS_AWARDED_SUBQUERY } = require('./db-tasks');
|
|
47
48
|
|
|
48
49
|
const SKY_CACHE_TTL_MS = 60 * 1000;
|
|
49
50
|
|
|
@@ -92,9 +93,12 @@ async function skyRows({ versionId = null, viewerId = null, viewerIsArchon = fal
|
|
|
92
93
|
// Compact by construction: no description, no value summary, no notes.
|
|
93
94
|
// created_at is truncated to the DAY in SQL so the payload carries ten
|
|
94
95
|
// characters per task, not twenty-seven, and the clock draws by day anyway.
|
|
96
|
+
// credits_awarded (task 1004781) is the shared settled-only payout subquery; its
|
|
97
|
+
// per-row lookup rides idx_credit_log_task (core_189), never a scan of the log.
|
|
95
98
|
`SELECT t.id::text AS id, t.goal_id::text AS goal_id, t.title, t.status,
|
|
96
99
|
t.credits_reward, t.created_at::date::text AS created_on,
|
|
97
|
-
CASE WHEN t.source_ref ~ '^idea:[0-9]+$' THEN substring(t.source_ref from 6) END AS idea_id
|
|
100
|
+
CASE WHEN t.source_ref ~ '^idea:[0-9]+$' THEN substring(t.source_ref from 6) END AS idea_id,
|
|
101
|
+
${CREDITS_AWARDED_SUBQUERY} AS credits_awarded
|
|
98
102
|
FROM tasks t
|
|
99
103
|
JOIN goals g ON g.id = t.goal_id
|
|
100
104
|
WHERE ($1::text IS NULL OR g.version_id = $1)
|
|
@@ -189,6 +193,9 @@ function shapeSky({ goals = [], edges = [], extras = [], criteria = [], tasks =
|
|
|
189
193
|
title: visible ? t.title : null,
|
|
190
194
|
status: t.status,
|
|
191
195
|
credits_reward: t.credits_reward == null ? null : Number(t.credits_reward),
|
|
196
|
+
// task 1004781 — what the ledger actually paid (0 until settled), so the
|
|
197
|
+
// sky sizes a well by money paid, never by the estimate.
|
|
198
|
+
credits_awarded: t.credits_awarded == null ? 0 : Number(t.credits_awarded),
|
|
192
199
|
created_on: t.created_on || null,
|
|
193
200
|
idea_id: t.idea_id != null ? String(t.idea_id) : null,
|
|
194
201
|
});
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.171",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.21.
|
|
9
|
+
"version": "1.21.171",
|
|
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.21.
|
|
3
|
+
"version": "1.21.171",
|
|
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
|
@@ -10094,5 +10094,11 @@
|
|
|
10094
10094
|
"id": "1003806",
|
|
10095
10095
|
"text": "When a new module version is being tested, how it went for the testing projects now counts toward its quality score — and a handful of friendly testers can no longer outscore hundreds of real ones."
|
|
10096
10096
|
}
|
|
10097
|
+
],
|
|
10098
|
+
"1.21.171": [
|
|
10099
|
+
{
|
|
10100
|
+
"id": "1004781",
|
|
10101
|
+
"text": "Credit figures in the hall now show money that was actually paid. A finished task shows its real payout instead of the old guess, so goal totals, member stats and the goal map stop adding up estimates as if they were earnings."
|
|
10102
|
+
}
|
|
10097
10103
|
]
|
|
10098
10104
|
}
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.21.
|
|
78
|
+
const CORE_VERSION = '1.21.171'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
package/tests/goal_map_page.mjs
CHANGED
|
@@ -60,14 +60,14 @@ function well(over = {}) {
|
|
|
60
60
|
{ id: '71', criterion_id: 'c2', criterion_md: 'The second ring is open', satisfied: false, pending_review: false, task_ids: ['501', '502'] },
|
|
61
61
|
],
|
|
62
62
|
tasks: [
|
|
63
|
-
{ id: '500', title: 'The task', status: 'shipped', credits_reward: 60, created_on: '2026-07-01', idea_id: '10' },
|
|
63
|
+
{ id: '500', title: 'The task', status: 'shipped', credits_reward: 60, credits_awarded: 60, created_on: '2026-07-01', idea_id: '10' },
|
|
64
64
|
{ id: '501', title: 'A held task', status: 'active', credits_reward: 40, created_on: '2026-08-01', idea_id: null },
|
|
65
65
|
{ id: '502', title: 'A claimable task', status: 'ready', credits_reward: 30, created_on: '2026-08-02', idea_id: null },
|
|
66
66
|
],
|
|
67
67
|
...over,
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
const tasksOf = (prefix, n, status, created = '2026-05-01') => Array.from({ length: n }, (_, i) => ({ id: `${prefix}${i}`, title: `task ${prefix}${i}`, status, credits_reward: 20, created_on: created, idea_id: null }));
|
|
70
|
+
const tasksOf = (prefix, n, status, created = '2026-05-01') => Array.from({ length: n }, (_, i) => ({ id: `${prefix}${i}`, title: `task ${prefix}${i}`, status, credits_reward: 20, credits_awarded: status === 'shipped' ? 20 : 0, created_on: created, idea_id: null }));
|
|
71
71
|
// A quiet well: nothing held, nothing landed this week.
|
|
72
72
|
const quiet = (over = {}) => well({ goal_id: '9', title: 'A quiet well — nothing moves', task_total: 4, task_done: 4, criteria: [], tasks: tasksOf('9-', 4, 'shipped'), ...over });
|
|
73
73
|
const settled = (over = {}) => well({ goal_id: '8', title: 'A settled system — it finished', status: 'achieved', task_total: 3, task_done: 3, tasks: tasksOf('8-', 3, 'shipped'), created_at: '2026-03-01T00:00:00.000Z', ...over });
|
|
@@ -142,7 +142,7 @@ await test('a goal is a well sized by its credits; settled and collapsed goals k
|
|
|
142
142
|
assert.equal(o.mass, 60);
|
|
143
143
|
assert.ok(Math.abs(a.r - o.r * 0.8) < 1e-9, 'a settled system is 0.8× the well it would have been');
|
|
144
144
|
assert.ok(Math.abs(c.r - o.r * 0.5) < 1e-9, 'a collapsed goal is half');
|
|
145
|
-
const big = await boot({ sky: sky([well(same({ goal_id: '1' })), well({ ...same({ goal_id: '4' }), tasks: tasksOf('4-', 3, 'shipped').map((t) => ({ ...t, credits_reward: 400 })) })]) });
|
|
145
|
+
const big = await boot({ sky: sky([well(same({ goal_id: '1' })), well({ ...same({ goal_id: '4' }), tasks: tasksOf('4-', 3, 'shipped').map((t) => ({ ...t, credits_reward: 400, credits_awarded: 400 })) })]) });
|
|
146
146
|
assert.ok(goal(big, '4').r > goal(big, '1').r, 'more credits, a bigger well');
|
|
147
147
|
});
|
|
148
148
|
|
|
@@ -227,7 +227,7 @@ await test('EXPLORE IS ON BY DEFAULT: the sky asks where you begin, and the ledg
|
|
|
227
227
|
assert.equal(p.el('start').hidden, false, '"where do you begin" is up');
|
|
228
228
|
const opts = p.el('startOpts').querySelectorAll('button');
|
|
229
229
|
assert.equal(opts[0].textContent, 'where my thoughts are');
|
|
230
|
-
assert.deepEqual(opts.slice(1, -1).map((b) => b.dataset.start), ['
|
|
230
|
+
assert.deepEqual(opts.slice(1, -1).map((b) => b.dataset.start), ['9', '7'], 'one door per open well, biggest first (task 1004781: 7 weighs only the 60 it paid now)');
|
|
231
231
|
assert.equal(opts.at(-1).textContent, 'show me everything');
|
|
232
232
|
assert.equal(SKY.seen(goal(p, '7')), false, 'nothing is reached yet');
|
|
233
233
|
p.key('l');
|
|
@@ -283,7 +283,7 @@ await test('THE LEDGER IS THE ACCESSIBLE PATH: every goal is a row, both directi
|
|
|
283
283
|
assert.ok(rows.includes(SKY.esc(g.title)), `${g.title} is named whole`);
|
|
284
284
|
}
|
|
285
285
|
const rowOf = (id) => (new RegExp(`data-id="${id}"[\\s\\S]*?</button>`).exec(rows) || [''])[0];
|
|
286
|
-
assert.match(rowOf('7'), /alive · 1\/3 tasks ·
|
|
286
|
+
assert.match(rowOf('7'), /alive · 1\/3 tasks · 60 cr · 1\/2 rings · waits on 1/, 'the waiting goal (alive: a task is held) counts what it waits on');
|
|
287
287
|
assert.match(rowOf('9'), /waited on by 1/, 'the goal waited on counts it the other way');
|
|
288
288
|
assert.match(rowOf('8'), /settled/); assert.match(rowOf('6'), /collapsed/);
|
|
289
289
|
const filters = p.el('filters').querySelectorAll('button').map((b) => [b.dataset.f, b.textContent.replace(/\s*\d+$/, '').trim()]);
|
package/tests/hall_sky.mjs
CHANGED
|
@@ -92,7 +92,7 @@ function well(over = {}) {
|
|
|
92
92
|
{ id: '71', criterion_id: 'c2', criterion_md: 'The second ring is open', satisfied: false, pending_review: false, task_ids: ['501', '502'] },
|
|
93
93
|
],
|
|
94
94
|
tasks: [
|
|
95
|
-
{ id: '500', title: 'The task', status: 'shipped', credits_reward: 60, created_on: '2026-07-01', idea_id: '10' },
|
|
95
|
+
{ id: '500', title: 'The task', status: 'shipped', credits_reward: 60, credits_awarded: 6, created_on: '2026-07-01', idea_id: '10' },
|
|
96
96
|
{ id: '501', title: 'A held task', status: 'active', credits_reward: 40, created_on: '2026-08-01', idea_id: null },
|
|
97
97
|
{ id: '502', title: 'A claimable task', status: 'ready', credits_reward: 30, created_on: '2026-08-02', idea_id: null },
|
|
98
98
|
],
|
|
@@ -211,7 +211,18 @@ await test('the rings are the criteria, closing as each is satisfied and thick w
|
|
|
211
211
|
const g = p.S().goalById.get('7');
|
|
212
212
|
assert.equal(g.crit.length, 2);
|
|
213
213
|
same(g.crit.map((c) => c.satisfied), [true, false]);
|
|
214
|
-
|
|
214
|
+
// task 1004781 — a ring weighs what its tasks were PAID: the shipped task paid 6 (its 60 was a guess), and
|
|
215
|
+
// the held and claimable tasks have paid nothing yet, so their estimates stay off the ring.
|
|
216
|
+
same(g.crit.map((c) => c.credits), [6, 0], 'a ring\'s credits are what the tasks on it were paid');
|
|
217
|
+
assert.equal(g.tasks.find((t) => t.id === '500').estimate, null, 'a settled task carries no estimate');
|
|
218
|
+
assert.equal(g.tasks.find((t) => t.id === '501').estimate, 40, 'live work keeps its estimate, apart from the total');
|
|
219
|
+
const SKY = p.SKY();
|
|
220
|
+
SKY.pick({ kind: 'task', ref: g.tasks.find((t) => t.id === '501') }, false);
|
|
221
|
+
assert.match(p.panel(), /40 <span class="lbl">Est\.<\/span>/, 'the panel labels a live task\'s figure as an estimate');
|
|
222
|
+
assert.doesNotMatch(p.panel(), /credits paid/);
|
|
223
|
+
SKY.pick({ kind: 'task', ref: g.tasks.find((t) => t.id === '500') }, false);
|
|
224
|
+
assert.match(p.panel(), /credits paid[\s\S]*?6/, 'and a settled task\'s as what it was paid');
|
|
225
|
+
assert.doesNotMatch(p.panel(), /Est\./);
|
|
215
226
|
assert.equal(g.tasks.find((t) => t.id === '500').ci, 0, 'a task knows which ring it gates');
|
|
216
227
|
assert.equal(g.tasks.find((t) => t.id === '500').sourceRef, '10', 'and which thought it was born of');
|
|
217
228
|
});
|
|
@@ -230,8 +241,9 @@ await test('abandoned work is listed at zero and adds nothing to a well or its r
|
|
|
230
241
|
const g = p.S().goalById.get('7');
|
|
231
242
|
assert.equal(g.tasks.find((t) => t.id === '503').credits, 0, 'still listed, at zero');
|
|
232
243
|
assert.equal(g.tasks.find((t) => t.id === '504').credits, 0, 'a merged-away task is listed at zero too');
|
|
233
|
-
assert.equal(g.credits,
|
|
234
|
-
same(g.crit.map((c) => c.credits), [
|
|
244
|
+
assert.equal(g.credits, 6, 'the well\'s mass is what was paid only');
|
|
245
|
+
same(g.crit.map((c) => c.credits), [6, 0], 'and the ring it sat on is not thickened by it');
|
|
246
|
+
assert.equal(g.tasks.find((t) => t.id === '503').estimate, null, 'abandoned work carries no estimate either');
|
|
235
247
|
});
|
|
236
248
|
|
|
237
249
|
await test('a private goal keeps its structure and none of its prose', async () => {
|
|
@@ -136,14 +136,27 @@ function loadBrandApply(rewardBlock) {
|
|
|
136
136
|
const SHIPPED_TASK = { status: 'shipped', credits_awarded: 0, credits_reward: 60 };
|
|
137
137
|
const READY_TASK = { status: 'ready', credits_reward: 60 };
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
// task 1004781 — a settled task shows what it was PAID, never its estimate:
|
|
140
|
+
// the 60 is not a payout, so a shipped task with nothing in the ledger is 0,
|
|
141
|
+
// and that 0 is an actual figure (plain label). Only live work is "Est.".
|
|
142
|
+
test('hall: cost-plus-only shows a SHIPPED task as what it paid (0), not the 60 estimate', () => {
|
|
140
143
|
const B = loadBrandApply(CPO);
|
|
141
|
-
assert.equal(B.
|
|
142
|
-
|
|
144
|
+
assert.equal(B.taskCreditValue(SHIPPED_TASK), 0, 'the estimate must never stand in for a payout');
|
|
145
|
+
assert.equal(B.taskCreditLabel(SHIPPED_TASK), 'credits');
|
|
146
|
+
assert.equal(B.taskCreditValue({ ...SHIPPED_TASK, credits_awarded: 7 }), 7, 'a real payout shows as itself');
|
|
147
|
+
assert.equal(B.taskCreditValue(READY_TASK), 60, 'live work keeps its estimate');
|
|
143
148
|
assert.equal(B.taskCreditLabel(READY_TASK), 'credits Est.');
|
|
144
149
|
assert.equal(B.perTaskCredit(), false);
|
|
145
150
|
});
|
|
146
151
|
|
|
152
|
+
test('hall: a settled task never falls back to its estimate, on any reward mode', () => {
|
|
153
|
+
for (const mode of [CPO, PAYS, undefined]) {
|
|
154
|
+
const B = loadBrandApply(mode);
|
|
155
|
+
assert.equal(B.taskCreditValue(SHIPPED_TASK), 0);
|
|
156
|
+
assert.equal(B.taskCreditValue({ status: 'confirmed', credits_reward: 30 }), 0, 'no ledger figure ⇒ 0');
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
147
160
|
test('hall: a PAYING instance keeps the original settled/unsettled split', () => {
|
|
148
161
|
const B = loadBrandApply(PAYS);
|
|
149
162
|
assert.equal(B.taskCreditLabel(SHIPPED_TASK), 'credits', 'settled ⇒ plain label, unchanged');
|
package/tests/sky_read.mjs
CHANGED
|
@@ -56,14 +56,14 @@ await test('the shape: wells carry their criteria and their compact tasks; edges
|
|
|
56
56
|
assert.equal(w1.created_at, '2026-09-01T00:00:00.000Z');
|
|
57
57
|
// task 1004402: each ring also carries its UAT state + backend-only flag (ADR 0351).
|
|
58
58
|
assert.deepEqual(w1.criteria, [{ id: '10', criterion_id: 'slug-10', criterion_md: 'Criterion 10', satisfied: false, backend_only: false, task_ids: ['100', '101'], pending_review: false, uat_state: 'open' }]);
|
|
59
|
-
assert.deepEqual(w1.tasks[0], { id: '100', title: 'Task 100', status: 'shipped', credits_reward: 30, created_on: '2026-09-02', idea_id: '555' });
|
|
59
|
+
assert.deepEqual(w1.tasks[0], { id: '100', title: 'Task 100', status: 'shipped', credits_reward: 30, credits_awarded: 0, created_on: '2026-09-02', idea_id: '555' });
|
|
60
60
|
assert.equal(w1.tasks[1].idea_id, null, 'a task not born of an idea carries null, not an empty string');
|
|
61
61
|
assert.deepEqual(out.goals[1].criteria[0].task_ids, [], 'a criterion with no linked task is an empty ring, not a missing one');
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
await test('nothing but the compact fields rides on a task — no description, no value summary, no notes', () => {
|
|
65
65
|
const out = shapeSky({ goals: [g(1)], extras: [x(1)], tasks: [t(1, 1, { description: 'long prose', value_summary: 'more prose', notes: 'and more' })] });
|
|
66
|
-
assert.deepEqual(Object.keys(out.goals[0].tasks[0]).sort(), ['created_on', 'credits_reward', 'id', 'idea_id', 'status', 'title']);
|
|
66
|
+
assert.deepEqual(Object.keys(out.goals[0].tasks[0]).sort(), ['created_on', 'credits_awarded', 'credits_reward', 'id', 'idea_id', 'status', 'title']);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
await test('a ring or a task under a goal that is not a well is dropped, not drawn to nowhere', () => {
|
|
@@ -177,6 +177,17 @@ await test('the criterion→task join is read ONCE for every goal-bearing criter
|
|
|
177
177
|
assert.match(crit[0].sql, /LEFT JOIN tasks t\s+ON t\.id = tc\.task_id/, 'a criterion with no task still arrives (the rollup\'s LEFT JOIN)');
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
+
// task 1004781 — the sky sizes wells by what the ledger PAID, so the read
|
|
181
|
+
// carries the payout (the shared subquery, settled-only) beside the estimate.
|
|
182
|
+
await test('a task carries what the ledger paid for it, from the shared payout subquery', async () => {
|
|
183
|
+
const out = shapeSky({ goals: [g(1)], extras: [x(1)], tasks: [t(100, 1, { status: 'shipped', credits_awarded: '7' })] });
|
|
184
|
+
assert.equal(out.goals[0].tasks[0].credits_awarded, 7);
|
|
185
|
+
const pool = fakePool();
|
|
186
|
+
await skyRows({}, { pool });
|
|
187
|
+
const tq = pool.calls.find((c) => /FROM tasks t\s+JOIN goals g/.test(c.sql));
|
|
188
|
+
assert.match(tq.sql, /FROM credit_log cl[\s\S]*AS credits_awarded/);
|
|
189
|
+
});
|
|
190
|
+
|
|
180
191
|
await test('the task query is compact by construction: no description, no value_summary, and the date is truncated in SQL', async () => {
|
|
181
192
|
const pool = fakePool();
|
|
182
193
|
await skyRows({}, { pool });
|