@bongos/core 1.19.900 → 1.19.902
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 +39 -24
- package/docs/copy-inventory.md +8 -7
- package/docs/copy-registry.json +17 -8
- package/docs/module-api-changelog.md +4 -0
- package/modules/economy/credits.js +216 -9
- package/modules/economy/reward-policy.js +34 -1
- package/modules/economy/reward.js +4 -0
- package/modules/hall-ui/public/profile.js +51 -5
- package/modules/ideas/descent.js +103 -32
- package/modules/ideas/module.json +2 -1
- package/modules/ideas/routes/inbox.js +36 -0
- package/modules/ideas/trail-descent.js +224 -0
- package/modules/lifecycle/db-ship.js +15 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +1 -1
- package/tests/helpers.mjs +137 -0
- package/tests/idea_descent_ship_credit.mjs +481 -0
- package/tests/idea_task_descent.mjs +9 -2
- package/tests/idea_trail_descent.mjs +399 -0
- package/tests/profile_activity.mjs +4 -122
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.902",
|
|
6
|
+
"core_contract": "1.19.902",
|
|
7
|
+
"source_commit": "2ec480ac926f1b9c899eef2576b1e6a7409e9013",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-20T07:49:00.223Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 502,
|
|
13
13
|
"agent_docs_stubbed": 26,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2284,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2812,
|
|
20
|
+
"tree_sha256": "e1c4784e88618bc042732cabcda2e40e5af8c8a4f21282de67baa72990fe7b6b",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2097,12 +2097,12 @@
|
|
|
2097
2097
|
{
|
|
2098
2098
|
"path": "docs/copy-inventory.md",
|
|
2099
2099
|
"mode": "0000644",
|
|
2100
|
-
"sha256": "
|
|
2100
|
+
"sha256": "bee7d1411eaf22aaaf7887b53e1151a0654055f8b4a7f6d78802b1eea766aa71"
|
|
2101
2101
|
},
|
|
2102
2102
|
{
|
|
2103
2103
|
"path": "docs/copy-registry.json",
|
|
2104
2104
|
"mode": "0000644",
|
|
2105
|
-
"sha256": "
|
|
2105
|
+
"sha256": "120d68ae5ad77ce670704ccd385b14b523ff7a530742b0038788e480084c6e34"
|
|
2106
2106
|
},
|
|
2107
2107
|
{
|
|
2108
2108
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2632,7 +2632,7 @@
|
|
|
2632
2632
|
{
|
|
2633
2633
|
"path": "docs/module-api-changelog.md",
|
|
2634
2634
|
"mode": "0000644",
|
|
2635
|
-
"sha256": "
|
|
2635
|
+
"sha256": "367d63ea84eaa28d8ccbadc967d41fb94a689906a8d8438e8b6a123c6ff4489e"
|
|
2636
2636
|
},
|
|
2637
2637
|
{
|
|
2638
2638
|
"path": "docs/modules-contract.md",
|
|
@@ -4182,7 +4182,7 @@
|
|
|
4182
4182
|
{
|
|
4183
4183
|
"path": "modules/economy/credits.js",
|
|
4184
4184
|
"mode": "0000644",
|
|
4185
|
-
"sha256": "
|
|
4185
|
+
"sha256": "b0f36f5d71bc376e090b14c6c95b3ac005fecd464e59bc73213d1d3a2b662469"
|
|
4186
4186
|
},
|
|
4187
4187
|
{
|
|
4188
4188
|
"path": "modules/economy/migrations/economy_001_fix_gds_shipper_description.sql",
|
|
@@ -4202,12 +4202,12 @@
|
|
|
4202
4202
|
{
|
|
4203
4203
|
"path": "modules/economy/reward-policy.js",
|
|
4204
4204
|
"mode": "0000644",
|
|
4205
|
-
"sha256": "
|
|
4205
|
+
"sha256": "817f400faa29aabcfdeb98eabeca45790203dff2dbca2ed01336d69078dd2be2"
|
|
4206
4206
|
},
|
|
4207
4207
|
{
|
|
4208
4208
|
"path": "modules/economy/reward.js",
|
|
4209
4209
|
"mode": "0000644",
|
|
4210
|
-
"sha256": "
|
|
4210
|
+
"sha256": "05f2aa731ed9bfc19088c0c6a59e0f91c6096806285e74e74b48f4530bcfa5f0"
|
|
4211
4211
|
},
|
|
4212
4212
|
{
|
|
4213
4213
|
"path": "modules/economy/routes/cost.js",
|
|
@@ -5037,7 +5037,7 @@
|
|
|
5037
5037
|
{
|
|
5038
5038
|
"path": "modules/hall-ui/public/profile.js",
|
|
5039
5039
|
"mode": "0000644",
|
|
5040
|
-
"sha256": "
|
|
5040
|
+
"sha256": "0ca0433fa846d12e2ea2d69084ad406d6e23fbe92e20c7364da4e92e54e26cf4"
|
|
5041
5041
|
},
|
|
5042
5042
|
{
|
|
5043
5043
|
"path": "modules/hall-ui/public/profile.states.json",
|
|
@@ -5312,7 +5312,7 @@
|
|
|
5312
5312
|
{
|
|
5313
5313
|
"path": "modules/ideas/descent.js",
|
|
5314
5314
|
"mode": "0000644",
|
|
5315
|
-
"sha256": "
|
|
5315
|
+
"sha256": "778558f148d8b403b64f0714b27436b08c41ae0d21ed18b4ed73939928e05cd4"
|
|
5316
5316
|
},
|
|
5317
5317
|
{
|
|
5318
5318
|
"path": "modules/ideas/homeless-home.js",
|
|
@@ -5362,7 +5362,7 @@
|
|
|
5362
5362
|
{
|
|
5363
5363
|
"path": "modules/ideas/module.json",
|
|
5364
5364
|
"mode": "0000644",
|
|
5365
|
-
"sha256": "
|
|
5365
|
+
"sha256": "c23099e7c3a4768dc68778292c42988ee21234ed81d1832347e9fd272f6137d9"
|
|
5366
5366
|
},
|
|
5367
5367
|
{
|
|
5368
5368
|
"path": "modules/ideas/pollers/descent-writer.js",
|
|
@@ -5377,7 +5377,7 @@
|
|
|
5377
5377
|
{
|
|
5378
5378
|
"path": "modules/ideas/routes/inbox.js",
|
|
5379
5379
|
"mode": "0000644",
|
|
5380
|
-
"sha256": "
|
|
5380
|
+
"sha256": "d4c91dcc603e4fc72ef6110a32350b2f59df19858f83a70962645a7fa09a55c4"
|
|
5381
5381
|
},
|
|
5382
5382
|
{
|
|
5383
5383
|
"path": "modules/ideas/routing.js",
|
|
@@ -5394,6 +5394,11 @@
|
|
|
5394
5394
|
"mode": "0000644",
|
|
5395
5395
|
"sha256": "eade9a2d07da0a39af17c086d188a195be00c544889d61454ed3c6368d39ea04"
|
|
5396
5396
|
},
|
|
5397
|
+
{
|
|
5398
|
+
"path": "modules/ideas/trail-descent.js",
|
|
5399
|
+
"mode": "0000644",
|
|
5400
|
+
"sha256": "2d0693b00dded081b6a0082c450762763d324d54f098a8f42a9aa25ec27370c4"
|
|
5401
|
+
},
|
|
5397
5402
|
{
|
|
5398
5403
|
"path": "modules/lifecycle/CLAUDE.md",
|
|
5399
5404
|
"mode": "0000644",
|
|
@@ -5512,7 +5517,7 @@
|
|
|
5512
5517
|
{
|
|
5513
5518
|
"path": "modules/lifecycle/db-ship.js",
|
|
5514
5519
|
"mode": "0000644",
|
|
5515
|
-
"sha256": "
|
|
5520
|
+
"sha256": "14c269ad1bf569976421c71e0814d47338bd11f9382e9949e2e01f6f6f15f6c7"
|
|
5516
5521
|
},
|
|
5517
5522
|
{
|
|
5518
5523
|
"path": "modules/lifecycle/db-tasks.js",
|
|
@@ -7757,12 +7762,12 @@
|
|
|
7757
7762
|
{
|
|
7758
7763
|
"path": "package-lock.json",
|
|
7759
7764
|
"mode": "0000644",
|
|
7760
|
-
"sha256": "
|
|
7765
|
+
"sha256": "b072b5799f9a792ea474fc50364b099b477a89037abac29f31a80a4e0afd56a4"
|
|
7761
7766
|
},
|
|
7762
7767
|
{
|
|
7763
7768
|
"path": "package.json",
|
|
7764
7769
|
"mode": "0000644",
|
|
7765
|
-
"sha256": "
|
|
7770
|
+
"sha256": "70ca20ce45a63886eff37d367e9574ab1ecc6d77191d500bc9c080ac80e71f8a"
|
|
7766
7771
|
},
|
|
7767
7772
|
{
|
|
7768
7773
|
"path": "public-docs/index.html",
|
|
@@ -9772,7 +9777,7 @@
|
|
|
9772
9777
|
{
|
|
9773
9778
|
"path": "src/module-api.js",
|
|
9774
9779
|
"mode": "0000644",
|
|
9775
|
-
"sha256": "
|
|
9780
|
+
"sha256": "46c60fef08ac1cdeedec15a52a867d37f30a61e0ddbf9092a489fc7f5eae3a01"
|
|
9776
9781
|
},
|
|
9777
9782
|
{
|
|
9778
9783
|
"path": "src/module-loader/catalog.js",
|
|
@@ -11722,7 +11727,7 @@
|
|
|
11722
11727
|
{
|
|
11723
11728
|
"path": "tests/helpers.mjs",
|
|
11724
11729
|
"mode": "0000644",
|
|
11725
|
-
"sha256": "
|
|
11730
|
+
"sha256": "40b3377e8f1e69f5f3465297018c9e148582a23aca85d5ea5802c119620562c6"
|
|
11726
11731
|
},
|
|
11727
11732
|
{
|
|
11728
11733
|
"path": "tests/hierarchy-config.mjs",
|
|
@@ -11809,6 +11814,11 @@
|
|
|
11809
11814
|
"mode": "0000644",
|
|
11810
11815
|
"sha256": "3e43b2afa7ea9e8ccee99759c27f7ab28f7a49823cc3b7e921071714d2d0d7f1"
|
|
11811
11816
|
},
|
|
11817
|
+
{
|
|
11818
|
+
"path": "tests/idea_descent_ship_credit.mjs",
|
|
11819
|
+
"mode": "0000644",
|
|
11820
|
+
"sha256": "e2bc31f771f80549cf50f9614b5473485f6c9db9b9179f3830a76738e1247ac7"
|
|
11821
|
+
},
|
|
11812
11822
|
{
|
|
11813
11823
|
"path": "tests/idea_detail_page.mjs",
|
|
11814
11824
|
"mode": "0000644",
|
|
@@ -11887,7 +11897,7 @@
|
|
|
11887
11897
|
{
|
|
11888
11898
|
"path": "tests/idea_task_descent.mjs",
|
|
11889
11899
|
"mode": "0000644",
|
|
11890
|
-
"sha256": "
|
|
11900
|
+
"sha256": "36674ef87ccf2d10fca66f4999e62ec8c3518798618c1abfc77f3a6dcc9c330f"
|
|
11891
11901
|
},
|
|
11892
11902
|
{
|
|
11893
11903
|
"path": "tests/idea_task_lineage.mjs",
|
|
@@ -11904,6 +11914,11 @@
|
|
|
11904
11914
|
"mode": "0000644",
|
|
11905
11915
|
"sha256": "943afa2366f92c4d6188ce9f8d68f499aac8d67930f91d6860a2cb83020642ab"
|
|
11906
11916
|
},
|
|
11917
|
+
{
|
|
11918
|
+
"path": "tests/idea_trail_descent.mjs",
|
|
11919
|
+
"mode": "0000644",
|
|
11920
|
+
"sha256": "00701012dbdc9c4d9cb2484aeff4426cb1af0a4643bd979211b361b00af80c69"
|
|
11921
|
+
},
|
|
11907
11922
|
{
|
|
11908
11923
|
"path": "tests/idea_triage.mjs",
|
|
11909
11924
|
"mode": "0000644",
|
|
@@ -12577,7 +12592,7 @@
|
|
|
12577
12592
|
{
|
|
12578
12593
|
"path": "tests/profile_activity.mjs",
|
|
12579
12594
|
"mode": "0000644",
|
|
12580
|
-
"sha256": "
|
|
12595
|
+
"sha256": "483d249339dd696809a4d9ac53aa10d7b67a35ce064884ef5590cc7249418047"
|
|
12581
12596
|
},
|
|
12582
12597
|
{
|
|
12583
12598
|
"path": "tests/profile_connections_ui.mjs",
|
package/docs/copy-inventory.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
> Deterministic on a given tree — regenerate and commit rather than hand-editing.
|
|
5
5
|
> Machine-readable twin: [`copy-registry.json`](copy-registry.json).
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**1827 strings** across 3 surfaces · 1585 distinct pieces of copy · 1827 certain, 0 heuristic · 166 shown in more than one place.
|
|
8
8
|
|
|
9
9
|
## Surfaces
|
|
10
10
|
|
|
11
11
|
| surface | lives at | files | strings |
|
|
12
12
|
|---|---|---|---|
|
|
13
|
-
| `builders-hall` | `modules/hall-ui/public` | 84 |
|
|
13
|
+
| `builders-hall` | `modules/hall-ui/public` | 84 | 1337 |
|
|
14
14
|
| `status-dashboard` | `modules/status-ui/public` | 4 | 100 |
|
|
15
15
|
| `landing` | `modules/public-landing/public` | 5 | 390 |
|
|
16
16
|
|
|
@@ -78,7 +78,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
78
78
|
| `996edffc1966` | 2x | Access requests | modules/hall-ui/public/watch.html:46, modules/hall-ui/public/watch.html:61 |
|
|
79
79
|
| … | | _126 more in the JSON registry_ | |
|
|
80
80
|
|
|
81
|
-
## `builders-hall` —
|
|
81
|
+
## `builders-hall` — 1337 strings
|
|
82
82
|
|
|
83
83
|
| id | conf | text | where |
|
|
84
84
|
|---|---|---|---|
|
|
@@ -309,7 +309,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
309
309
|
| `7775fec0fa85` | certain | Could not load sessions. | `modules/hall-ui/public/sessions.js:437` |
|
|
310
310
|
| `a2f2e8babef5` | certain | Could not load that page. Try again. | `modules/hall-ui/public/blockers.js:274` |
|
|
311
311
|
| `b2147cc90e36` | certain | Could not load the idea template. Reload, or file from the terminal with capture.js. | `modules/hall-ui/public/ideas.js:626` |
|
|
312
|
-
| `7604af13c40e` | certain | Could not load the profile. | `modules/hall-ui/public/profile.js:
|
|
312
|
+
| `7604af13c40e` | certain | Could not load the profile. | `modules/hall-ui/public/profile.js:836` |
|
|
313
313
|
| `8b69e445592a` | certain | Could not load the question labels; showing the answers as stored. | `modules/hall-ui/public/idea.js:244` |
|
|
314
314
|
| `edd5bafbe075` | certain | Could not load the queue just now. | `modules/hall-ui/public/ideas.js:565` |
|
|
315
315
|
| `02bb0570996a` | certain | Could not load the ranks. | `modules/hall-ui/public/ranks.js:197` |
|
|
@@ -601,7 +601,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
601
601
|
| `6e73716aec6c` | certain | May be offered for sale later | `modules/hall-ui/public/settings.html:297` |
|
|
602
602
|
| `df335a1224ae` | certain | Member since {…} | `modules/hall-ui/public/hall-render.js:563` |
|
|
603
603
|
| `df335a1224ae` | certain | Member since {…} | `modules/hall-ui/public/profile.js:94` |
|
|
604
|
-
| `c7a670e9552d` | certain | Merged into | `modules/hall-ui/public/profile.js:
|
|
604
|
+
| `c7a670e9552d` | certain | Merged into | `modules/hall-ui/public/profile.js:452` |
|
|
605
605
|
| `dce0546c9e34` | certain | Merging work does not put it in front of anyone. This is the step that does: it moves this platform — or any p | `modules/hall-ui/public/deploy.html:39` |
|
|
606
606
|
| `7637613c231b` | certain | Metic rank and above may vote | `modules/hall-ui/public/builders.js:781` |
|
|
607
607
|
| `91328a97fe68` | certain | Mingle pairs you with someone from another role. Saying no costs nothing. | `modules/hall-ui/public/collab.html:87` |
|
|
@@ -919,7 +919,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
919
919
|
| `9d4372b173cf` | certain | Standing sections | `modules/hall-ui/public/index.html:79` |
|
|
920
920
|
| `ec1c2dae4a90` | certain | Standing there | `modules/hall-ui/public/profile.js:314` |
|
|
921
921
|
| `eaad12cacb9d` | certain | Start over | `modules/hall-ui/public/studio.js:235` |
|
|
922
|
-
| `efe530c0e3a7` | certain | Still open | `modules/hall-ui/public/profile.js:
|
|
922
|
+
| `efe530c0e3a7` | certain | Still open | `modules/hall-ui/public/profile.js:457` |
|
|
923
923
|
| `9a4ced1afb6c` | certain | Stop waiting on task {…} | `modules/hall-ui/public/task.js:278` |
|
|
924
924
|
| `b0861c874a2f` | certain | Stopped using it. | `modules/hall-ui/public/settings-specialities.js:200` |
|
|
925
925
|
| `6c6544f5c011` | certain | Stored encrypted; never shown again after saving — only its last four digits. | `modules/hall-ui/public/settings.html:193` |
|
|
@@ -1180,6 +1180,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1180
1180
|
| `bc960f460250` | certain | and install dependencies ( | `modules/hall-ui/public/hall-render.js:864` |
|
|
1181
1181
|
| `2177da93be9b` | certain | and leave this alone. | `modules/hall-ui/public/settings.html:339` |
|
|
1182
1182
|
| `b867876e8b6c` | certain | and press Enter. | `modules/hall-ui/public/hall-render.js:825` |
|
|
1183
|
+
| `0257cb508ae7` | certain | and {…} more below this thought | `modules/hall-ui/public/profile.js:415` |
|
|
1183
1184
|
| `d86265f99668` | certain | and {…} more waiting{…} | `modules/hall-ui/public/studio.js:277` |
|
|
1184
1185
|
| `520853131591` | certain | artist mode | `modules/hall-ui/public/studio.html:36` |
|
|
1185
1186
|
| `b4033000c537` | certain | as a table | `modules/hall-ui/public/profile-charts.js:205` |
|
|
@@ -1352,7 +1353,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1352
1353
|
| `cc5106af4b35` | certain | {…} of {…} criteria satisfied | `modules/hall-ui/public/goals-lib.js:32` |
|
|
1353
1354
|
| `cc5106af4b35` | certain | {…} of {…} criteria satisfied | `modules/hall-ui/public/goals-render.js:682` |
|
|
1354
1355
|
| `cc5106af4b35` | certain | {…} of {…} criteria satisfied | `modules/hall-ui/public/goals.js:45` |
|
|
1355
|
-
| `c3d9687e2375` | certain | {…} of {…} shipped | `modules/hall-ui/public/profile.js:
|
|
1356
|
+
| `c3d9687e2375` | certain | {…} of {…} shipped | `modules/hall-ui/public/profile.js:558` |
|
|
1356
1357
|
| `f32710d0ef37` | certain | {…} of {…} steps cleared. | `modules/hall-ui/public/hall-render.js:1037` |
|
|
1357
1358
|
| `60743fe1e40d` | certain | {…} per page | `modules/hall-ui/public/hall-kit.js:74` |
|
|
1358
1359
|
| `154bc518bab4` | certain | {…} proposed | `modules/hall-ui/public/government.js:695` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"generator": "scripts/gds/copy-inventory.js",
|
|
4
4
|
"goal": 1000074,
|
|
5
5
|
"counts": {
|
|
6
|
-
"strings":
|
|
7
|
-
"unique_ids":
|
|
8
|
-
"certain":
|
|
6
|
+
"strings": 1827,
|
|
7
|
+
"unique_ids": 1585,
|
|
8
|
+
"certain": 1827,
|
|
9
9
|
"heuristic": 0,
|
|
10
10
|
"duplicate_ids": 166
|
|
11
11
|
},
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"builders-hall": {
|
|
14
14
|
"at": "modules/hall-ui/public",
|
|
15
15
|
"files": 84,
|
|
16
|
-
"strings":
|
|
16
|
+
"strings": 1337
|
|
17
17
|
},
|
|
18
18
|
"status-dashboard": {
|
|
19
19
|
"at": "modules/status-ui/public",
|
|
@@ -3824,7 +3824,7 @@
|
|
|
3824
3824
|
"surface": "builders-hall",
|
|
3825
3825
|
"text": "Could not load the profile.",
|
|
3826
3826
|
"file": "modules/hall-ui/public/profile.js",
|
|
3827
|
-
"line":
|
|
3827
|
+
"line": 836,
|
|
3828
3828
|
"origin": "js-notice",
|
|
3829
3829
|
"confidence": "certain"
|
|
3830
3830
|
},
|
|
@@ -6452,7 +6452,7 @@
|
|
|
6452
6452
|
"surface": "builders-hall",
|
|
6453
6453
|
"text": "Merged into",
|
|
6454
6454
|
"file": "modules/hall-ui/public/profile.js",
|
|
6455
|
-
"line":
|
|
6455
|
+
"line": 452,
|
|
6456
6456
|
"origin": "js-markup",
|
|
6457
6457
|
"confidence": "certain"
|
|
6458
6458
|
},
|
|
@@ -9314,7 +9314,7 @@
|
|
|
9314
9314
|
"surface": "builders-hall",
|
|
9315
9315
|
"text": "Still open",
|
|
9316
9316
|
"file": "modules/hall-ui/public/profile.js",
|
|
9317
|
-
"line":
|
|
9317
|
+
"line": 457,
|
|
9318
9318
|
"origin": "js-markup",
|
|
9319
9319
|
"confidence": "certain"
|
|
9320
9320
|
},
|
|
@@ -11658,6 +11658,15 @@
|
|
|
11658
11658
|
"origin": "js-markup",
|
|
11659
11659
|
"confidence": "certain"
|
|
11660
11660
|
},
|
|
11661
|
+
{
|
|
11662
|
+
"id": "0257cb508ae7",
|
|
11663
|
+
"surface": "builders-hall",
|
|
11664
|
+
"text": "and {…} more below this thought",
|
|
11665
|
+
"file": "modules/hall-ui/public/profile.js",
|
|
11666
|
+
"line": 415,
|
|
11667
|
+
"origin": "js-markup",
|
|
11668
|
+
"confidence": "certain"
|
|
11669
|
+
},
|
|
11661
11670
|
{
|
|
11662
11671
|
"id": "d86265f99668",
|
|
11663
11672
|
"surface": "builders-hall",
|
|
@@ -13211,7 +13220,7 @@
|
|
|
13211
13220
|
"surface": "builders-hall",
|
|
13212
13221
|
"text": "{…} of {…} shipped",
|
|
13213
13222
|
"file": "modules/hall-ui/public/profile.js",
|
|
13214
|
-
"line":
|
|
13223
|
+
"line": 558,
|
|
13215
13224
|
"origin": "js-markup",
|
|
13216
13225
|
"confidence": "certain"
|
|
13217
13226
|
},
|
|
@@ -2274,5 +2274,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2274
2274
|
landed since 1.19.898 with no explicit bump. run 35488237998. (task 1002620)
|
|
2275
2275
|
1.19.900 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2276
2276
|
landed since 1.19.899 with no explicit bump. run 35492534307. (task 1002620)
|
|
2277
|
+
1.19.901 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2278
|
+
landed since 1.19.900 with no explicit bump. run 35494090938. (task 1002620)
|
|
2279
|
+
1.19.902 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2280
|
+
landed since 1.19.901 with no explicit bump. run 35497860558. (task 1002620)
|
|
2277
2281
|
---------------------------------------------------------------------------
|
|
2278
2282
|
```
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// (db.applyGrade/confirmTask/upsertSessionRecordWithReward) resolves these
|
|
10
10
|
// through the `reward` kernel PORT rather than importing this module.
|
|
11
11
|
|
|
12
|
-
const { pool, branding } = require('../../src/module-api');
|
|
12
|
+
const { pool, branding, resolveOptional } = require('../../src/module-api');
|
|
13
13
|
const { priceModelUsage, PRICES } = require('../../src/module-api').llmPricing; // cost-plus session reward (task 1005)
|
|
14
14
|
const achievements = require('./achievements');
|
|
15
15
|
|
|
@@ -157,7 +157,7 @@ const IDEA_GOVERNANCE_PASS_FLOOR = 30; // owner: floor ~30 — see the note on
|
|
|
157
157
|
// Re-exported below, so this module is still the one place reward resolution lives
|
|
158
158
|
// (ADR 0146) and every existing caller is unchanged.
|
|
159
159
|
const {
|
|
160
|
-
REWARD_MARGIN_PCT, REWARD_MODE_DEFAULT, REWARD_MODE_COST_PLUS_ONLY, rewardPolicy,
|
|
160
|
+
REWARD_MARGIN_PCT, REWARD_MODE_DEFAULT, REWARD_MODE_COST_PLUS_ONLY, IDEA_DESCENT_DECAY, rewardPolicy,
|
|
161
161
|
} = require('./reward-policy');
|
|
162
162
|
|
|
163
163
|
// Per-instance reward policy, resolved over the code defaults. Stays HERE, not in
|
|
@@ -502,6 +502,40 @@ async function awardIdeaFullPassCredit(client, { ideaId, authorId, completenessS
|
|
|
502
502
|
};
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
+
// descentPayoutMaxDepth — the deepest hop that can still pay a single credit.
|
|
506
|
+
//
|
|
507
|
+
// The decayed share is base × factor × decay^d, and the best case for factor is
|
|
508
|
+
// 1 (a 100%-complete Full Idea). Once that rounds to 0 no deeper ancestor can
|
|
509
|
+
// ever be paid, whatever its grade, so walking further is pure round trips.
|
|
510
|
+
// Returned as a DEPTH CAP for the walk rather than a break in the payout loop,
|
|
511
|
+
// because the round trips happen inside the walk, not in the loop.
|
|
512
|
+
//
|
|
513
|
+
// Derived, never picked: at the default half it comes out at 4, and a steeper
|
|
514
|
+
// rate gives a smaller number. DESCENT_MAX_DEPTH remains the outer backstop.
|
|
515
|
+
function descentPayoutMaxDepth(decay, base = IDEA_TASK_SHIP_BASE, cap = 64) {
|
|
516
|
+
if (!(decay > 0)) return 0;
|
|
517
|
+
for (let d = 1; d <= cap; d += 1) {
|
|
518
|
+
if (Math.round(base * Math.pow(decay, d)) <= 0) return d - 1;
|
|
519
|
+
}
|
|
520
|
+
return cap;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// ideaGradeFactor — what one shipped task under an idea is worth, BEFORE depth.
|
|
524
|
+
//
|
|
525
|
+
// A Full Idea earns in proportion to its completeness; a Quick or Spark idea
|
|
526
|
+
// (no completeness score) earns the flat quick factor. A full idea with no score
|
|
527
|
+
// yet also falls back to the quick factor rather than 0 — the work shipped, and
|
|
528
|
+
// the idea is at least quick-grade.
|
|
529
|
+
//
|
|
530
|
+
// EXTRACTED so the direct payout and the decayed descent payout below cannot
|
|
531
|
+
// disagree about what an idea's work is worth: the two differ only by the decay
|
|
532
|
+
// term, and a second copy of this clamp would make them differ by more.
|
|
533
|
+
function ideaGradeFactor(grade, completeness) {
|
|
534
|
+
return (grade === 'full' && completeness != null && Number.isFinite(Number(completeness)))
|
|
535
|
+
? Math.max(0, Math.min(1, Number(completeness) / 100))
|
|
536
|
+
: QUICK_IDEA_FACTOR;
|
|
537
|
+
}
|
|
538
|
+
|
|
505
539
|
// Stream 1 (ADR 0172 / goal 1000067 IC4): as each task descended from an idea
|
|
506
540
|
// SHIPS, pay the idea's author IDEA_TASK_SHIP_BASE credits, SCALED by the idea's
|
|
507
541
|
// grade — a Full Idea by its completeness, a Quick/Spark idea by a flat factor.
|
|
@@ -560,13 +594,7 @@ async function awardIdeaTaskShipCredit(client, { taskId, config = rewardConfig()
|
|
|
560
594
|
return { credited: 0, reason: 'no_source_idea', ideaId: null, authorId: null };
|
|
561
595
|
}
|
|
562
596
|
const { idea_id: ideaId, captured_by: authorId, grade, completeness, developed_by: developedBy } = rows[0];
|
|
563
|
-
|
|
564
|
-
// or Spark idea (no completeness score) earns the flat quick factor. A full
|
|
565
|
-
// idea with no score yet also falls back to the quick factor rather than 0 —
|
|
566
|
-
// the work shipped, the idea is at least quick-grade.
|
|
567
|
-
const factor = (grade === 'full' && completeness != null && Number.isFinite(Number(completeness)))
|
|
568
|
-
? Math.max(0, Math.min(1, Number(completeness) / 100))
|
|
569
|
-
: QUICK_IDEA_FACTOR;
|
|
597
|
+
const factor = ideaGradeFactor(grade, completeness);
|
|
570
598
|
const delta = Math.round(IDEA_TASK_SHIP_BASE * factor);
|
|
571
599
|
if (delta <= 0) {
|
|
572
600
|
return { credited: 0, reason: 'zero_after_scaling', ideaId: Number(ideaId), authorId: Number(authorId) };
|
|
@@ -592,6 +620,184 @@ async function awardIdeaTaskShipCredit(client, { taskId, config = rewardConfig()
|
|
|
592
620
|
: { credited: 0, reason: 'already_paid', ideaId: Number(ideaId), authorId: Number(authorId) };
|
|
593
621
|
}
|
|
594
622
|
|
|
623
|
+
// awardIdeaDescentShipCredit — the same stream 1 payout, for the origins the
|
|
624
|
+
// shipping task descends from RATHER THAN the one it was promoted from
|
|
625
|
+
// (task 1004088, BV2.R09; ADR 0312, spec decisions 6 + 7 + 16).
|
|
626
|
+
//
|
|
627
|
+
// WHAT WAS MISSING. awardIdeaTaskShipCredit above pays the idea whose
|
|
628
|
+
// ideas_task_lineage row names THIS task. That is one hop. A task split off a
|
|
629
|
+
// task an idea produced, a cascade its ship fired, a child of a child — all of
|
|
630
|
+
// them ship and pay the origin nothing, because the origin is not on their
|
|
631
|
+
// lineage row and never will be. The idea's descent grew; its ledger did not.
|
|
632
|
+
//
|
|
633
|
+
// THE RULE: full share at the direct task, `decay` per hop below it. At the
|
|
634
|
+
// default half, an unbounded descent is worth at most twice the direct task, so
|
|
635
|
+
// the series converges and no hop limit has to be invented. The rate is a
|
|
636
|
+
// per-instance dial (config.ideaDescentDecay; modules/economy/reward-policy.js).
|
|
637
|
+
//
|
|
638
|
+
// THE BOUNDARY THAT STOPS FARMING (spec decision 7): DESCENDANT WORK pays the
|
|
639
|
+
// origin; a separate thought that merely cites it does not. Nothing here reads
|
|
640
|
+
// an idea→idea relation — not merged_into_idea_id, not the trail's merge follow.
|
|
641
|
+
// It walks ideas_task_descent, which carries only task→task edges the system
|
|
642
|
+
// derived from a cascade, a split or a fold. That asymmetry is deliberate and is
|
|
643
|
+
// the difference between the two surfaces: the descent DISPLAYS more than the
|
|
644
|
+
// payout COUNTS.
|
|
645
|
+
//
|
|
646
|
+
// ONE PAYMENT PER ORIGIN PER SHIP, AT THE SHORTEST DEPTH. A merge makes the
|
|
647
|
+
// descent a DAG, so one origin can sit above a shipping task by two routes of
|
|
648
|
+
// different length, and two ancestors can share a source idea. Each origin is
|
|
649
|
+
// therefore resolved once, at the smallest depth — the same rule the walk itself
|
|
650
|
+
// applies, for the same reason: at two depths it would be paid twice for one
|
|
651
|
+
// piece of work. The reason key is already per (idea, task), so the ledger would
|
|
652
|
+
// have caught the duplicate; resolving it here means the RETURNED numbers are
|
|
653
|
+
// right too, rather than depending on which booking ran first.
|
|
654
|
+
//
|
|
655
|
+
// FAIL-SOFT AROUND THE WALK, NOT AROUND THE MONEY. If the ideas module is absent
|
|
656
|
+
// (no provider) or has no edges yet, this returns nothing paid and the direct
|
|
657
|
+
// payout above is untouched — which is exactly today's behaviour, and is what
|
|
658
|
+
// "existing first-hop behaviour preserved" means. A walk that THROWS is a
|
|
659
|
+
// different matter and is left to propagate: this runs inside the ship
|
|
660
|
+
// transaction beside the direct credit, and silently swallowing a failure here
|
|
661
|
+
// would under-pay an origin with no record that it happened.
|
|
662
|
+
//
|
|
663
|
+
// client — pg client / pool (transaction participant)
|
|
664
|
+
// taskId — the task that just shipped
|
|
665
|
+
// skipIdeaIds — origins already paid for this ship at depth 0, so the direct
|
|
666
|
+
// payout always wins over a decayed one for the same idea
|
|
667
|
+
// config — resolved reward policy; gates on config.ideatorCredit
|
|
668
|
+
//
|
|
669
|
+
// Returns { credited, reason, payments: [{ ideaId, depth, delta, payees }] }.
|
|
670
|
+
async function awardIdeaDescentShipCredit(client, { taskId, skipIdeaIds = [], config = rewardConfig() } = {}) {
|
|
671
|
+
if (config && config.ideatorCredit === false) {
|
|
672
|
+
return { credited: 0, reason: 'ideator_lane_off', payments: [] };
|
|
673
|
+
}
|
|
674
|
+
// BOUNDED HERE TOO, not only in rewardPolicy(). This is a PORT method: the
|
|
675
|
+
// reward port hands it to any module that resolves it, and a caller may pass
|
|
676
|
+
// its own `config` object that never went through the resolver. A rate of 1
|
|
677
|
+
// or more does not converge — the comment on IDEA_DESCENT_DECAY promises it
|
|
678
|
+
// cannot happen, and a promise the function does not enforce is a promise the
|
|
679
|
+
// next caller breaks. Out of range falls back to the default, exactly as the
|
|
680
|
+
// resolver does, rather than throwing inside a ship transaction.
|
|
681
|
+
const rawDecay = (config && config.ideaDescentDecay) == null
|
|
682
|
+
? NaN
|
|
683
|
+
: Number(config.ideaDescentDecay);
|
|
684
|
+
const decay = Number.isFinite(rawDecay) && rawDecay >= 0 && rawDecay < 1
|
|
685
|
+
? rawDecay
|
|
686
|
+
: IDEA_DESCENT_DECAY;
|
|
687
|
+
// 0 means "only the direct task pays" — a legal instance setting, and the
|
|
688
|
+
// cheapest possible answer, so it short-circuits before the walk.
|
|
689
|
+
if (!(decay > 0)) return { credited: 0, reason: 'decay_off', payments: [] };
|
|
690
|
+
|
|
691
|
+
// The walk lives in the ideas module and is reached through the switchboard:
|
|
692
|
+
// a module may not require a sibling (ADR 0083 rule 1), and a second copy of
|
|
693
|
+
// a breadth-first shortest-depth walk would drift into a different amount of
|
|
694
|
+
// money. resolveOptional, because an instance running without the ideas
|
|
695
|
+
// module has no descent to follow and must still ship tasks.
|
|
696
|
+
const port = resolveOptional && resolveOptional('ideas.descent');
|
|
697
|
+
if (!port || typeof port.ancestorsOfTask !== 'function') {
|
|
698
|
+
return { credited: 0, reason: 'no_descent_port', payments: [] };
|
|
699
|
+
}
|
|
700
|
+
// DON'T WALK FURTHER THAN THE MONEY REACHES. Past the depth at which even a
|
|
701
|
+
// 100%-complete idea's decayed share stops rounding to a credit, every
|
|
702
|
+
// remaining hop is a round trip that provably pays nobody. The cap is derived
|
|
703
|
+
// from the rate rather than picked: at the default half it is 4, and a
|
|
704
|
+
// shallower rate makes it smaller, not larger. Bounded by the walk's own
|
|
705
|
+
// DESCENT_MAX_DEPTH, which stays the backstop.
|
|
706
|
+
const maxDepth = descentPayoutMaxDepth(decay);
|
|
707
|
+
const ancestors = await port.ancestorsOfTask(taskId, { client, maxDepth });
|
|
708
|
+
if (!ancestors || ancestors.length === 0) {
|
|
709
|
+
return { credited: 0, reason: 'no_ancestors', payments: [] };
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// The shortest depth at which each ancestor TASK sits above this ship.
|
|
713
|
+
// ancestorsOfTask already returns nearest-first with each node once, so the
|
|
714
|
+
// first sighting is the shortest; the map is here so the lookup below cannot
|
|
715
|
+
// accidentally read a later one.
|
|
716
|
+
const depthByTask = new Map();
|
|
717
|
+
for (const a of ancestors) {
|
|
718
|
+
const key = String(a.id);
|
|
719
|
+
if (!depthByTask.has(key)) depthByTask.set(key, a.depth);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Which idea each ancestor task came from — ONE query, not one per ancestor.
|
|
723
|
+
// DISTINCT ON picks the EARLIEST lineage link per task, which is the same rule
|
|
724
|
+
// awardIdeaTaskShipCredit applies to the direct task (task 1003515 / ADR 0236:
|
|
725
|
+
// a task subsumed from several ideas keeps a row for each, so the read must
|
|
726
|
+
// choose, and it must choose the way the trail and inbox.sourceIdeaForTask do
|
|
727
|
+
// or the ledger and the money name different ideas).
|
|
728
|
+
const { rows } = await client.query(
|
|
729
|
+
`SELECT DISTINCT ON (l.task_id)
|
|
730
|
+
l.task_id,
|
|
731
|
+
l.idea_id,
|
|
732
|
+
i.captured_by,
|
|
733
|
+
COALESCE(g.grade, 'quick') AS grade,
|
|
734
|
+
g.completeness_score AS completeness,
|
|
735
|
+
g.developed_by AS developed_by
|
|
736
|
+
FROM ideas_task_lineage l
|
|
737
|
+
JOIN idea_inbox i ON i.id = l.idea_id
|
|
738
|
+
LEFT JOIN ideas_grades g ON g.idea_id = l.idea_id
|
|
739
|
+
WHERE l.task_id = ANY($1::bigint[])
|
|
740
|
+
ORDER BY l.task_id, l.created_at ASC, l.idea_id ASC`,
|
|
741
|
+
[[...depthByTask.keys()].map(Number)]
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
// Collapse ancestor tasks onto their ORIGINS: two ancestors can share one
|
|
745
|
+
// source idea, and that idea is owed one payment at the shallower of the two.
|
|
746
|
+
const skip = new Set((skipIdeaIds || []).map(String));
|
|
747
|
+
const byIdea = new Map();
|
|
748
|
+
for (const row of rows) {
|
|
749
|
+
if (row.captured_by == null) continue;
|
|
750
|
+
const ideaKey = String(row.idea_id);
|
|
751
|
+
if (skip.has(ideaKey)) continue; // already paid in full at depth 0
|
|
752
|
+
const depth = depthByTask.get(String(row.task_id));
|
|
753
|
+
if (!Number.isInteger(depth) || depth < 1) continue;
|
|
754
|
+
const prev = byIdea.get(ideaKey);
|
|
755
|
+
if (prev && prev.depth <= depth) continue;
|
|
756
|
+
byIdea.set(ideaKey, { row, depth });
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const payments = [];
|
|
760
|
+
let credited = 0;
|
|
761
|
+
// Nearest origins first, so a partially-booked run resumes in a stable order
|
|
762
|
+
// and the returned list reads the way the descent does.
|
|
763
|
+
const ordered = [...byIdea.values()].sort((a, b) => a.depth - b.depth || Number(a.row.idea_id) - Number(b.row.idea_id));
|
|
764
|
+
for (const { row, depth } of ordered) {
|
|
765
|
+
const { idea_id: ideaId, captured_by: authorId, grade, completeness, developed_by: developedBy } = row;
|
|
766
|
+
// The SAME grade factor the direct payout applies — a Full Idea earns in
|
|
767
|
+
// proportion to its completeness, a Quick or Spark idea the flat factor.
|
|
768
|
+
// Spelled through the shared helper so the two paths cannot disagree about
|
|
769
|
+
// what an idea's work is worth before depth is taken into account.
|
|
770
|
+
const factor = ideaGradeFactor(grade, completeness);
|
|
771
|
+
// ROUNDED ONCE, at the end. Rounding per hop would compound the error, and
|
|
772
|
+
// rounding to zero IS the floor the spec's open question asked about: a
|
|
773
|
+
// descendant stops paying when its decayed share no longer rounds to a
|
|
774
|
+
// credit, which needs no separately-chosen hop limit.
|
|
775
|
+
const delta = Math.round(IDEA_TASK_SHIP_BASE * factor * Math.pow(decay, depth));
|
|
776
|
+
if (delta <= 0) continue;
|
|
777
|
+
const payees = splitIdeaCredit(delta, { authorId, developedBy });
|
|
778
|
+
if (payees.length === 0) continue;
|
|
779
|
+
// THE SAME REASON KEY the direct payout uses — per (idea, task), not per
|
|
780
|
+
// (idea, task, depth). An origin is paid once for one ship however the
|
|
781
|
+
// descent is re-walked, and a re-run after a partial failure is safe.
|
|
782
|
+
const reason = `idea.credit.task_ship:${ideaId}:${taskId}`;
|
|
783
|
+
const gradeLabel = `${grade}${completeness != null ? ` ${Math.round(Number(completeness))}%` : ''}`;
|
|
784
|
+
const { credited: paid, payees: booked } = await bookIdeaSplit(client, {
|
|
785
|
+
payees,
|
|
786
|
+
reason,
|
|
787
|
+
taskId,
|
|
788
|
+
describe: (p) => `Task #${taskId} shipped ${depth} hop${depth === 1 ? '' : 's'} below idea #${ideaId} (${gradeLabel}) → ${p.delta}c to its ${p.role.replace(/_/g, ' ')} (ideator lane stream 1, decayed by depth, BV2.R09/ADR 0312)`,
|
|
789
|
+
});
|
|
790
|
+
credited += paid;
|
|
791
|
+
payments.push({ ideaId: Number(ideaId), depth, delta, credited: paid, payees: booked });
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
return {
|
|
795
|
+
credited,
|
|
796
|
+
reason: credited > 0 ? 'paid' : (payments.length > 0 ? 'already_paid' : 'nothing_to_pay'),
|
|
797
|
+
payments,
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
|
|
595
801
|
// Stream 3 (ADR 0172 / goal 1000067 IC5): a Full Idea that PASSES the Board
|
|
596
802
|
// Room's ratification vote pays a share of a 100-credit ceiling, scaled by the
|
|
597
803
|
// idea's R142 completeness — "70%-complete + passes = 70". The ideator lane, so
|
|
@@ -1059,6 +1265,7 @@ module.exports = {
|
|
|
1059
1265
|
maybeAwardIdeaPromotionBonus,
|
|
1060
1266
|
awardIdeaFullPassCredit,
|
|
1061
1267
|
awardIdeaTaskShipCredit,
|
|
1268
|
+
awardIdeaDescentShipCredit,
|
|
1062
1269
|
awardIdeaGovernancePassCredit,
|
|
1063
1270
|
// the spark-handoff split (task 1002923 / BV1.R147, ADR 0185)
|
|
1064
1271
|
splitIdeaCredit,
|