@bongos/core 1.19.903 → 1.19.905

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 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.903",
6
- "core_contract": "1.19.903",
7
- "source_commit": "53ab83b870bf45e758ab22a2fb93103bfa42e51d",
5
+ "core_version": "1.19.905",
6
+ "core_contract": "1.19.905",
7
+ "source_commit": "dc5ca8cc91d1d88f957f722664f60778d2bdc4f1",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-20T12:28:20.291Z",
9
+ "built_at": "2026-09-20T13:17:59.483Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 502,
13
13
  "agent_docs_stubbed": 26,
14
- "functional_verbatim": 2278,
14
+ "functional_verbatim": 2283,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2806,
20
- "tree_sha256": "80c42879b74b051029afdcbf6fdcbbf26804064e32ea7abbcdc58a4fa44811fb",
19
+ "file_count": 2811,
20
+ "tree_sha256": "85790109607eeddc8439f8473f642747ed158cfb88a269f55222c30bc45016e5",
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": "bee7d1411eaf22aaaf7887b53e1151a0654055f8b4a7f6d78802b1eea766aa71"
2100
+ "sha256": "3e657714f3647bfb041f4eda9e4982a2b60747c4aceec0d8d8cbf8ee0de6eb47"
2101
2101
  },
2102
2102
  {
2103
2103
  "path": "docs/copy-registry.json",
2104
2104
  "mode": "0000644",
2105
- "sha256": "120d68ae5ad77ce670704ccd385b14b523ff7a530742b0038788e480084c6e34"
2105
+ "sha256": "1ba7f556256ee4cbb637b9809698c69aff529c080131949b4055058f8fb4716b"
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": "d6d904e3287c4286cd615dc97eb5d48295c06da5b430cb799aec003a34bdc5a1"
2635
+ "sha256": "ade94268540de319c8d071b7b70654fca4cb4bdd7bcfbbfe8ddca5710329545b"
2636
2636
  },
2637
2637
  {
2638
2638
  "path": "docs/modules-contract.md",
@@ -3734,6 +3734,11 @@
3734
3734
  "mode": "0000644",
3735
3735
  "sha256": "599449a48b3850eb457a34630a7bd5d95d354602f1a9e9b887593183a457cd21"
3736
3736
  },
3737
+ {
3738
+ "path": "migrations/core_251_credit_log_idea_size_index.sql",
3739
+ "mode": "0000644",
3740
+ "sha256": "75bb644b32a70b52ac544edb901abff91aad07701848a470cc52103dc7e74234"
3741
+ },
3737
3742
  {
3738
3743
  "path": "modules/agents/CLAUDE.md",
3739
3744
  "mode": "0000644",
@@ -4182,7 +4187,17 @@
4182
4187
  {
4183
4188
  "path": "modules/economy/credits.js",
4184
4189
  "mode": "0000644",
4185
- "sha256": "b0f36f5d71bc376e090b14c6c95b3ac005fecd464e59bc73213d1d3a2b662469"
4190
+ "sha256": "736eed2c89863d6eb28072627a40ac4f8945832cfb7b1d1aba10e6cc65483901"
4191
+ },
4192
+ {
4193
+ "path": "modules/economy/idea-size-historical.js",
4194
+ "mode": "0000644",
4195
+ "sha256": "f99f62eb4eaeda10b32284dbe27f87e64d5b6b82c9eb4aa442057d0de13be761"
4196
+ },
4197
+ {
4198
+ "path": "modules/economy/idea-size.js",
4199
+ "mode": "0000644",
4200
+ "sha256": "d1fa5fda6b34bd2a8cf8d563c780bc4b12f1cdfb955e13f51799a589609ac1c0"
4186
4201
  },
4187
4202
  {
4188
4203
  "path": "modules/economy/migrations/economy_001_fix_gds_shipper_description.sql",
@@ -4207,7 +4222,7 @@
4207
4222
  {
4208
4223
  "path": "modules/economy/reward.js",
4209
4224
  "mode": "0000644",
4210
- "sha256": "05f2aa731ed9bfc19088c0c6a59e0f91c6096806285e74e74b48f4530bcfa5f0"
4225
+ "sha256": "ef4b939d83324c927dd1b1c8e3200212d0b5da973a87db6f9810c9c7edb942ad"
4211
4226
  },
4212
4227
  {
4213
4228
  "path": "modules/economy/routes/cost.js",
@@ -4647,7 +4662,7 @@
4647
4662
  {
4648
4663
  "path": "modules/hall-ui/public/collab-lib.js",
4649
4664
  "mode": "0000644",
4650
- "sha256": "c8c30e5f3cb5982a8218b6e8b135923c76b75604be553dcf3ed46fca0466e67f"
4665
+ "sha256": "bfadae8700cc22ea13f8bc39a3e2a1876b58da6151032e9a973402bc9bd0aaa7"
4651
4666
  },
4652
4667
  {
4653
4668
  "path": "modules/hall-ui/public/collab.css",
@@ -4662,7 +4677,7 @@
4662
4677
  {
4663
4678
  "path": "modules/hall-ui/public/collab.js",
4664
4679
  "mode": "0000644",
4665
- "sha256": "7d589e6c98f9f52831a9be9429493b49e68c3aa62f98f19cbcb77adbac70c0ca"
4680
+ "sha256": "91a0751cebcbc179f28ad1cac7a6c447f90369ae40f29e5f60c1bd934ac68f85"
4666
4681
  },
4667
4682
  {
4668
4683
  "path": "modules/hall-ui/public/collab.states.json",
@@ -5037,7 +5052,7 @@
5037
5052
  {
5038
5053
  "path": "modules/hall-ui/public/profile.js",
5039
5054
  "mode": "0000644",
5040
- "sha256": "0ca0433fa846d12e2ea2d69084ad406d6e23fbe92e20c7364da4e92e54e26cf4"
5055
+ "sha256": "04015850c00627f2439ec919358516c841d4c32c64a7ba18ca758b3804e804b5"
5041
5056
  },
5042
5057
  {
5043
5058
  "path": "modules/hall-ui/public/profile.states.json",
@@ -5377,7 +5392,7 @@
5377
5392
  {
5378
5393
  "path": "modules/ideas/routes/inbox.js",
5379
5394
  "mode": "0000644",
5380
- "sha256": "d4c91dcc603e4fc72ef6110a32350b2f59df19858f83a70962645a7fa09a55c4"
5395
+ "sha256": "cd4e4d741dcbc4bb581f86aeec5b1e17dfe630712a0e5466a108daba78c74429"
5381
5396
  },
5382
5397
  {
5383
5398
  "path": "modules/ideas/routing.js",
@@ -5399,6 +5414,11 @@
5399
5414
  "mode": "0000644",
5400
5415
  "sha256": "2d0693b00dded081b6a0082c450762763d324d54f098a8f42a9aa25ec27370c4"
5401
5416
  },
5417
+ {
5418
+ "path": "modules/ideas/trail-size.js",
5419
+ "mode": "0000644",
5420
+ "sha256": "f1e60dbc8c6dc0e9f5f5cb93bf26c659422503e8ec66937a3dcee5b64971e995"
5421
+ },
5402
5422
  {
5403
5423
  "path": "modules/lifecycle/CLAUDE.md",
5404
5424
  "mode": "0000644",
@@ -7762,12 +7782,12 @@
7762
7782
  {
7763
7783
  "path": "package-lock.json",
7764
7784
  "mode": "0000644",
7765
- "sha256": "20d17854b6e4522308515c26c6efe033baa02b0d1b86a40c211fddc2b0cecfde"
7785
+ "sha256": "3b60452f407da16a6c09df92482e570ca061e920dd7537a6f2f84569a13e0545"
7766
7786
  },
7767
7787
  {
7768
7788
  "path": "package.json",
7769
7789
  "mode": "0000644",
7770
- "sha256": "8ee9f9ba3532c45ffd794bbdcae1c6d8d38fad130d73cf9c5275787ccfb60e53"
7790
+ "sha256": "3af5e528e00f1047c76f56189ef168ea8c879f09762b735160b5c6d2e81f9d24"
7771
7791
  },
7772
7792
  {
7773
7793
  "path": "public-docs/index.html",
@@ -9762,7 +9782,7 @@
9762
9782
  {
9763
9783
  "path": "src/module-api.js",
9764
9784
  "mode": "0000644",
9765
- "sha256": "565add1bbddcccee0c1b0e3e748b36d607af667350a541338faf48025cbfb904"
9785
+ "sha256": "2489905dea4c9defd22089221f6dce7c522f9860e6b684c9e6cea03a2600a17d"
9766
9786
  },
9767
9787
  {
9768
9788
  "path": "src/module-loader/catalog.js",
@@ -10602,7 +10622,7 @@
10602
10622
  {
10603
10623
  "path": "tests/collab_page.mjs",
10604
10624
  "mode": "0000644",
10605
- "sha256": "d7bbf03d41d8808f5f86f333a9e925291a628b5e5b4cac483be34880a6d42d04"
10625
+ "sha256": "b710669fabe9e747fe37abf429356e80c1f7a36cd63ac308dda2a933243e2e6d"
10606
10626
  },
10607
10627
  {
10608
10628
  "path": "tests/compose_demo_credentials.mjs",
@@ -11849,6 +11869,11 @@
11849
11869
  "mode": "0000644",
11850
11870
  "sha256": "3a2c5d2e6c3231f69847e1e2aea073e78caf26228b500dbdf612b5bae354d0a2"
11851
11871
  },
11872
+ {
11873
+ "path": "tests/idea_size.mjs",
11874
+ "mode": "0000644",
11875
+ "sha256": "c307e7c796e7e9f30b38b04144b426895642ea2d978ea5ace0f701ba7744420c"
11876
+ },
11852
11877
  {
11853
11878
  "path": "tests/idea_spark_hall.mjs",
11854
11879
  "mode": "0000644",
@@ -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
- **1827 strings** across 3 surfaces · 1585 distinct pieces of copy · 1827 certain, 0 heuristic · 166 shown in more than one place.
7
+ **1826 strings** across 3 surfaces · 1584 distinct pieces of copy · 1826 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 | 1337 |
13
+ | `builders-hall` | `modules/hall-ui/public` | 84 | 1336 |
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` — 1337 strings
81
+ ## `builders-hall` — 1336 strings
82
82
 
83
83
  | id | conf | text | where |
84
84
  |---|---|---|---|
@@ -135,7 +135,6 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
135
135
  | `0b9adf029094` | certain | A task cannot wait for itself. | `modules/hall-ui/public/task.js:890` |
136
136
  | `0aaa0f2c4bdc` | certain | A title is required. | `modules/hall-ui/public/blockers.js:345` |
137
137
  | `daf73127afff` | certain | A word on why | `modules/hall-ui/public/hall-render.js:294` |
138
- | `9fe51a2e1e71` | certain | A {…} — you are a {…}. Mingle pairs across roles. | `modules/hall-ui/public/collab.js:421` |
139
138
  | `996edffc1966` | certain | Access requests | `modules/hall-ui/public/watch.html:46` |
140
139
  | `996edffc1966` | certain | Access requests | `modules/hall-ui/public/watch.html:61` |
141
140
  | `303f8d90266f` | certain | Achievements could not be loaded. | `modules/hall-ui/public/builders.js:1196` |
@@ -304,12 +303,12 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
304
303
  | `90691bceaf68` | certain | Could not load | `modules/hall-ui/public/task.js:982` |
305
304
  | `589a4cfc5442` | certain | Could not load idea {…}. | `modules/hall-ui/public/ideas.js:644` |
306
305
  | `192c893fc64e` | certain | Could not load modules. | `modules/hall-ui/public/modules.js:318` |
307
- | `8a4b590fa1a0` | certain | Could not load requests. | `modules/hall-ui/public/collab.js:514` |
306
+ | `9912c3835136` | certain | Could not load requests — reload to try again. | `modules/hall-ui/public/collab.js:529` |
308
307
  | `7775fec0fa85` | certain | Could not load sessions. | `modules/hall-ui/public/sessions.js:399` |
309
308
  | `7775fec0fa85` | certain | Could not load sessions. | `modules/hall-ui/public/sessions.js:437` |
310
309
  | `a2f2e8babef5` | certain | Could not load that page. Try again. | `modules/hall-ui/public/blockers.js:274` |
311
310
  | `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:836` |
311
+ | `7604af13c40e` | certain | Could not load the profile. | `modules/hall-ui/public/profile.js:873` |
313
312
  | `8b69e445592a` | certain | Could not load the question labels; showing the answers as stored. | `modules/hall-ui/public/idea.js:244` |
314
313
  | `edd5bafbe075` | certain | Could not load the queue just now. | `modules/hall-ui/public/ideas.js:565` |
315
314
  | `02bb0570996a` | certain | Could not load the ranks. | `modules/hall-ui/public/ranks.js:197` |
@@ -601,7 +600,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
601
600
  | `6e73716aec6c` | certain | May be offered for sale later | `modules/hall-ui/public/settings.html:297` |
602
601
  | `df335a1224ae` | certain | Member since {…} | `modules/hall-ui/public/hall-render.js:563` |
603
602
  | `df335a1224ae` | certain | Member since {…} | `modules/hall-ui/public/profile.js:94` |
604
- | `c7a670e9552d` | certain | Merged into | `modules/hall-ui/public/profile.js:452` |
603
+ | `c7a670e9552d` | certain | Merged into | `modules/hall-ui/public/profile.js:489` |
605
604
  | `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
605
  | `7637613c231b` | certain | Metic rank and above may vote | `modules/hall-ui/public/builders.js:781` |
607
606
  | `91328a97fe68` | certain | Mingle pairs you with someone from another role. Saying no costs nothing. | `modules/hall-ui/public/collab.html:87` |
@@ -669,7 +668,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
669
668
  | `c72e0bdb834a` | certain | Not declared in module.json — this is who ships the module. | `modules/hall-ui/public/modules.js:62` |
670
669
  | `361b353ded5e` | certain | Not enough shipped work yet to chart. | `modules/hall-ui/public/hall-widgets.js:184` |
671
670
  | `90230572d017` | certain | Not found | `modules/hall-ui/public/task.js:970` |
672
- | `8226c979db4d` | certain | Not now | `modules/hall-ui/public/collab.js:421` |
671
+ | `8226c979db4d` | certain | Not now | `modules/hall-ui/public/collab.js:435` |
673
672
  | `5ffcdc1a0176` | certain | Not scored — this builder’s own profile waived every signal, or the session predates this measure. | `modules/hall-ui/public/sessions.js:100` |
674
673
  | `61250b49a90b` | certain | Not scored. | `modules/hall-ui/public/idea.js:84` |
675
674
  | `8d6afe6def47` | certain | Not signed in | `modules/hall-ui/public/settings.html:40` |
@@ -847,7 +846,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
847
846
  | `42cbc20a6ec8` | certain | Saves when you press Save; your next | `modules/hall-ui/public/settings.html:136` |
848
847
  | `645dd8117cf3` | certain | Say why it is being retired — the reason goes in the record. | `modules/hall-ui/public/task.js:924` |
849
848
  | `fc9d783ed0f5` | certain | Say why it is better. Whoever reviews this decides it from your reason, without asking you. | `modules/hall-ui/public/copy-desk.js:446` |
850
- | `12c1ec21a2c6` | certain | Say yes | `modules/hall-ui/public/collab.js:421` |
849
+ | `12c1ec21a2c6` | certain | Say yes | `modules/hall-ui/public/collab.js:435` |
851
850
  | `46711f7bc3df` | certain | Search every string the product shows a person, by what it says or the file it lives in. | `modules/hall-ui/public/copy-desk.html:65` |
852
851
  | `5d2ba8e72fa1` | certain | Search failed. | `modules/hall-ui/public/copy-desk.js:343` |
853
852
  | `373a7639bcb9` | certain | Sections in this primer | `modules/hall-ui/public/primer.html:52` |
@@ -919,7 +918,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
919
918
  | `9d4372b173cf` | certain | Standing sections | `modules/hall-ui/public/index.html:79` |
920
919
  | `ec1c2dae4a90` | certain | Standing there | `modules/hall-ui/public/profile.js:314` |
921
920
  | `eaad12cacb9d` | certain | Start over | `modules/hall-ui/public/studio.js:235` |
922
- | `efe530c0e3a7` | certain | Still open | `modules/hall-ui/public/profile.js:457` |
921
+ | `efe530c0e3a7` | certain | Still open | `modules/hall-ui/public/profile.js:494` |
923
922
  | `9a4ced1afb6c` | certain | Stop waiting on task {…} | `modules/hall-ui/public/task.js:278` |
924
923
  | `b0861c874a2f` | certain | Stopped using it. | `modules/hall-ui/public/settings-specialities.js:200` |
925
924
  | `6c6544f5c011` | certain | Stored encrypted; never shown again after saving — only its last four digits. | `modules/hall-ui/public/settings.html:193` |
@@ -1353,7 +1352,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
1353
1352
  | `cc5106af4b35` | certain | {…} of {…} criteria satisfied | `modules/hall-ui/public/goals-lib.js:32` |
1354
1353
  | `cc5106af4b35` | certain | {…} of {…} criteria satisfied | `modules/hall-ui/public/goals-render.js:682` |
1355
1354
  | `cc5106af4b35` | certain | {…} of {…} criteria satisfied | `modules/hall-ui/public/goals.js:45` |
1356
- | `c3d9687e2375` | certain | {…} of {…} shipped | `modules/hall-ui/public/profile.js:558` |
1355
+ | `c3d9687e2375` | certain | {…} of {…} shipped | `modules/hall-ui/public/profile.js:595` |
1357
1356
  | `f32710d0ef37` | certain | {…} of {…} steps cleared. | `modules/hall-ui/public/hall-render.js:1037` |
1358
1357
  | `60743fe1e40d` | certain | {…} per page | `modules/hall-ui/public/hall-kit.js:74` |
1359
1358
  | `154bc518bab4` | certain | {…} proposed | `modules/hall-ui/public/government.js:695` |
@@ -3,9 +3,9 @@
3
3
  "generator": "scripts/gds/copy-inventory.js",
4
4
  "goal": 1000074,
5
5
  "counts": {
6
- "strings": 1827,
7
- "unique_ids": 1585,
8
- "certain": 1827,
6
+ "strings": 1826,
7
+ "unique_ids": 1584,
8
+ "certain": 1826,
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": 1337
16
+ "strings": 1336
17
17
  },
18
18
  "status-dashboard": {
19
19
  "at": "modules/status-ui/public",
@@ -2253,15 +2253,6 @@
2253
2253
  "origin": "js-markup",
2254
2254
  "confidence": "certain"
2255
2255
  },
2256
- {
2257
- "id": "9fe51a2e1e71",
2258
- "surface": "builders-hall",
2259
- "text": "A {…} — you are a {…}. Mingle pairs across roles.",
2260
- "file": "modules/hall-ui/public/collab.js",
2261
- "line": 421,
2262
- "origin": "js-markup",
2263
- "confidence": "certain"
2264
- },
2265
2256
  {
2266
2257
  "id": "996edffc1966",
2267
2258
  "surface": "builders-hall",
@@ -3775,11 +3766,11 @@
3775
3766
  "confidence": "certain"
3776
3767
  },
3777
3768
  {
3778
- "id": "8a4b590fa1a0",
3769
+ "id": "9912c3835136",
3779
3770
  "surface": "builders-hall",
3780
- "text": "Could not load requests.",
3771
+ "text": "Could not load requests — reload to try again.",
3781
3772
  "file": "modules/hall-ui/public/collab.js",
3782
- "line": 514,
3773
+ "line": 529,
3783
3774
  "origin": "js-text-assign",
3784
3775
  "confidence": "certain"
3785
3776
  },
@@ -3824,7 +3815,7 @@
3824
3815
  "surface": "builders-hall",
3825
3816
  "text": "Could not load the profile.",
3826
3817
  "file": "modules/hall-ui/public/profile.js",
3827
- "line": 836,
3818
+ "line": 873,
3828
3819
  "origin": "js-notice",
3829
3820
  "confidence": "certain"
3830
3821
  },
@@ -6452,7 +6443,7 @@
6452
6443
  "surface": "builders-hall",
6453
6444
  "text": "Merged into",
6454
6445
  "file": "modules/hall-ui/public/profile.js",
6455
- "line": 452,
6446
+ "line": 489,
6456
6447
  "origin": "js-markup",
6457
6448
  "confidence": "certain"
6458
6449
  },
@@ -7064,7 +7055,7 @@
7064
7055
  "surface": "builders-hall",
7065
7056
  "text": "Not now",
7066
7057
  "file": "modules/hall-ui/public/collab.js",
7067
- "line": 421,
7058
+ "line": 435,
7068
7059
  "origin": "js-markup",
7069
7060
  "confidence": "certain"
7070
7061
  },
@@ -8666,7 +8657,7 @@
8666
8657
  "surface": "builders-hall",
8667
8658
  "text": "Say yes",
8668
8659
  "file": "modules/hall-ui/public/collab.js",
8669
- "line": 421,
8660
+ "line": 435,
8670
8661
  "origin": "js-markup",
8671
8662
  "confidence": "certain"
8672
8663
  },
@@ -9314,7 +9305,7 @@
9314
9305
  "surface": "builders-hall",
9315
9306
  "text": "Still open",
9316
9307
  "file": "modules/hall-ui/public/profile.js",
9317
- "line": 457,
9308
+ "line": 494,
9318
9309
  "origin": "js-markup",
9319
9310
  "confidence": "certain"
9320
9311
  },
@@ -13220,7 +13211,7 @@
13220
13211
  "surface": "builders-hall",
13221
13212
  "text": "{…} of {…} shipped",
13222
13213
  "file": "modules/hall-ui/public/profile.js",
13223
- "line": 558,
13214
+ "line": 595,
13224
13215
  "origin": "js-markup",
13225
13216
  "confidence": "certain"
13226
13217
  },
@@ -2280,5 +2280,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
2280
2280
  landed since 1.19.901 with no explicit bump. run 35497860558. (task 1002620)
2281
2281
  1.19.903 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2282
2282
  landed since 1.19.902 with no explicit bump. run 35510679104. (task 1002620)
2283
+ 1.19.904 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2284
+ landed since 1.19.903 with no explicit bump. run 35511494246. (task 1002620)
2285
+ 1.19.905 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2286
+ landed since 1.19.904 with no explicit bump. run 35513060618. (task 1002620)
2283
2287
  ---------------------------------------------------------------------------
2284
2288
  ```
@@ -0,0 +1,61 @@
1
+ -- core_251 an index for SIZE -- the per-idea rollup of the stream-1 ledger
2
+ -- Applied under task 1004093 (BV2.R12, goal 1000095).
3
+ --
4
+ -- WHY. modules/economy/idea-size.js answers "what has this idea's descent
5
+ -- paid" by summing credit_log rows whose reason embeds the idea:
6
+ --
7
+ -- idea.credit.task_ship:<ideaId>:<taskId>
8
+ --
9
+ -- That needs no column and no new table -- the ledger already carries the
10
+ -- attribution, which is why this task needed no SCHEMA change. What it does
11
+ -- need is a way to reach those rows without reading the whole ledger.
12
+ --
13
+ -- WHAT IT COSTS WITHOUT ONE. credit_log is the whole-instance, append-only
14
+ -- credit ledger: every task payout, every session reward, every bonus, for
15
+ -- every builder, forever. The size read runs on GET /inbox/by-builder/:id --
16
+ -- an ordinary page view of a builder's idea trail -- so an unindexed version
17
+ -- is a sequential scan of the entire lifetime ledger on every such view, and
18
+ -- its cost grows with total credit events rather than with anything about the
19
+ -- idea being looked at. A grader panel flagged exactly this on the first round
20
+ -- of task 1004093, and it was right to.
21
+ --
22
+ -- THE SHAPE. A PARTIAL EXPRESSION index:
23
+ --
24
+ -- * the EXPRESSION is split_part(reason, ':', 2) -- the idea id, taken off
25
+ -- the separator. The read groups on that same expression rather than on a
26
+ -- per-idea LIKE, because a prefix match is correct only by virtue of its
27
+ -- trailing colon and dropping it makes idea 1 absorb every payout of ideas
28
+ -- 10, 100 and 1000, silently. An index on the expression is what lets the
29
+ -- honest form of the query stay cheap.
30
+ -- * PARTIAL on the stream-1 prefix, so the index covers only ideator
31
+ -- task-ship rows. Those are a small minority of credit_log: the bulk is
32
+ -- task.shipped and session.token_reward, whose split_part(reason,':',2) is
33
+ -- the empty string and which no size read will ever want. A full index
34
+ -- would be several times the size to answer the same questions.
35
+ --
36
+ -- THE PREDICATE IS A LITERAL ON BOTH SIDES, AND THAT IS LOAD-BEARING. Postgres
37
+ -- only uses a partial index when it can prove the query's WHERE implies the
38
+ -- index predicate, and it cannot prove that about a parameterised
39
+ -- `reason LIKE $1 || '%'` -- the parameter's value is not known when a generic
40
+ -- plan is made. So idea-size.js spells the prefix into the SQL TEXT as a
41
+ -- literal (validated at module load), matching the string below character for
42
+ -- character. If the two ever drift, nothing errors and nothing renders
43
+ -- differently: the index is simply never used again and the scan quietly comes
44
+ -- back. tests/idea_size.mjs reads THIS FILE and holds its predicate against the
45
+ -- economy constant, so the drift reds a test instead of a page.
46
+ --
47
+ -- THE UNDERSCORE IS ESCAPED, and it is not decoration. In LIKE, _ matches any
48
+ -- single character, so an unescaped 'idea.credit.task_ship:%' also matches
49
+ -- 'idea.credit.taskXship:'. No such key exists, which is precisely why nobody
50
+ -- would ever notice; backslash is LIKE's default escape in Postgres, so no
51
+ -- ESCAPE clause is needed and idea-size.js generates the identical string.
52
+ --
53
+ -- Additive and idempotent: it creates an index and touches no row. Not
54
+ -- CONCURRENTLY -- the migration runner wraps each file in a transaction and
55
+ -- CREATE INDEX CONCURRENTLY cannot run inside one. On an instance whose ledger
56
+ -- is large enough for that lock to matter, build it by hand outside the runner
57
+ -- and this statement becomes a no-op.
58
+
59
+ CREATE INDEX IF NOT EXISTS idx_credit_log_idea_task_ship
60
+ ON credit_log ((split_part(reason, ':', 2)))
61
+ WHERE reason LIKE 'idea.credit.task\_ship:%';
@@ -1273,6 +1273,14 @@ module.exports = {
1273
1273
  IDEA_FULL_PASS_CREDIT,
1274
1274
  IDEA_FULL_PASS_BAR,
1275
1275
  IDEA_TASK_SHIP_BASE,
1276
+ // The two pieces of the stream-1 payout ARITHMETIC, exported for
1277
+ // modules/economy/idea-size.js (task 1004097 / BV2.R18). A pre-existing
1278
+ // idea backfills the payouts its descent never received, and a second copy
1279
+ // of this arithmetic would make the backfilled figure differ from the money
1280
+ // the same descent will earn from now on — the exact drift the
1281
+ // ideaGradeFactor comment above exists to prevent.
1282
+ ideaGradeFactor,
1283
+ descentPayoutMaxDepth,
1276
1284
  QUICK_IDEA_FACTOR,
1277
1285
  IDEA_GOVERNANCE_PASS_MAX,
1278
1286
  IDEA_GOVERNANCE_PASS_FLOOR,
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ // modules/economy/idea-size-historical.js — THE HISTORICAL HALF OF SIZE
4
+ // (task 1004097, BV2.R18, goal 1000095; spec
5
+ // docs/specs/bongos-v2-ideator-surface.md decision 17).
6
+ //
7
+ // WHAT IS MISSING WITHOUT THIS, and it is not what the task title suggests.
8
+ // A pre-existing idea's ledger figure is not ABSENT, it is PARTIAL. Stream 1's
9
+ // direct payout has existed since ADR 0172, so a task promoted from an idea and
10
+ // shipped since then really was paid and really is in credit_log. What never
11
+ // happened is the DESCENT payout: awardIdeaDescentShipCredit only started
12
+ // paying with task 1004088, so every hop below the first, for every task that
13
+ // shipped before that, earned its origin nothing and never will.
14
+ //
15
+ // So the backfill is not "compute a size for ideas that have none". It is the
16
+ // GAP between the descent an idea actually has and the part of that descent the
17
+ // ledger was there to pay for.
18
+ //
19
+ // NO MONEY IS BOOKED (spec decision 17, the owner's ruling on interview Q6).
20
+ // Nothing here writes to credit_log, and nothing here is reachable from a ship
21
+ // path. The estimate is computed at READ time, every time, from the descent as
22
+ // it stands. Re-paying work already paid for once is exactly what the owner
23
+ // declined, and a backfill that wrote rows would also break stream 1's
24
+ // idempotency key — the ledger would then hold a payment for a ship that never
25
+ // triggered one.
26
+ //
27
+ // WHICH IS WHY THE TWO HALVES ARE KEPT APART RATHER THAN ADDED UP AND FORGOTTEN.
28
+ // `paid` is money that moved; `estimated` is money that did not. A single total
29
+ // with no marker is the number the spec calls a quiet lie, and the done-when
30
+ // asks for the opposite — that anywhere size is shown makes clear which kind of
31
+ // number it is. So this returns both, always, and the surfaces carry the split
32
+ // rather than a boolean bolted on at the end.
33
+ //
34
+ // THE ARITHMETIC IS NOT REIMPLEMENTED HERE. `ideaGradeFactor`,
35
+ // `descentPayoutMaxDepth` and `IDEA_TASK_SHIP_BASE` come from credits.js, which
36
+ // is where the real payout gets them. A second copy would make an idea's
37
+ // backfilled past disagree with the money the same descent earns from tomorrow
38
+ // — the same drift the "EXTRACTED so the two cannot disagree" note on
39
+ // ideaGradeFactor was written to prevent, one module over.
40
+
41
+ const {
42
+ IDEA_TASK_SHIP_BASE,
43
+ ideaGradeFactor,
44
+ descentPayoutMaxDepth,
45
+ } = require('./credits');
46
+
47
+ // priceDescentForIdea — PURE. What one idea's descent is worth, split into the
48
+ // part the ledger actually paid and the part it never did.
49
+ //
50
+ // tasks — every task under this idea, each { task_id, depth, status }.
51
+ // Depth 0 is a task the idea was promoted INTO; depth n is n
52
+ // hops below one of those. Shortest depth per task, which is the
53
+ // rule the walk and the payout both already apply.
54
+ // grade — the idea's grade ('quick' | 'spark' | 'full')
55
+ // completeness— its completeness score, or null
56
+ // decay — the resolved per-instance dial (reward-policy ideaDescentDecay)
57
+ // paidByTask — Map<taskIdString, creditsPaid> from credit_log, per task
58
+ //
59
+ // Returns { paid, estimated, payments, estimatedPayments }.
60
+ //
61
+ // ONLY A SHIPPED TASK COUNTS. The payout fires at ship, so a ready or abandoned
62
+ // descendant has earned its origin nothing and estimating for it would credit
63
+ // work that has not happened — the surface would then show a size that FELL
64
+ // when the task was later abandoned. Everything here is anchored on ships that
65
+ // actually occurred.
66
+ //
67
+ // PAID ALWAYS WINS FOR A TASK THE LEDGER KNOWS. If credit_log holds a payment
68
+ // for (idea, task), that figure is used verbatim and no estimate is made for it
69
+ // — money that moved is not re-derived. This is what keeps the paid half
70
+ // immutable while the arithmetic around it is free to change: a later decay dial
71
+ // or a re-scored completeness cannot retroactively alter what was banked.
72
+ //
73
+ // ROUNDED ONCE PER PAYMENT, the way the writer rounds — per (idea, task), never
74
+ // on the total. Rounding the sum would make the backfilled figure differ from
75
+ // what the same descent would have been paid hop by hop, which is the whole
76
+ // thing this function exists to reproduce.
77
+ function priceDescentForIdea({ tasks, grade, completeness, decay, paidByTask } = {}) {
78
+ const out = { paid: 0, estimated: 0, payments: 0, estimatedPayments: 0 };
79
+ const list = Array.isArray(tasks) ? tasks : [];
80
+ const paidMap = paidByTask instanceof Map ? paidByTask : new Map();
81
+
82
+ // A decay of 0 is a legal instance setting meaning "only the direct task
83
+ // pays", and it makes the cap 0 — so depth 0 is still priced and nothing
84
+ // below it is. Guarding on the cap rather than on the rate keeps that in one
85
+ // place.
86
+ const rate = Number.isFinite(Number(decay)) && Number(decay) >= 0 && Number(decay) < 1 ? Number(decay) : null;
87
+ if (rate === null) return out;
88
+ const maxDepth = descentPayoutMaxDepth(rate);
89
+ const factor = ideaGradeFactor(grade, completeness);
90
+
91
+ // One entry per task: a task reachable twice is one ship and owes one
92
+ // payment, at its shortest depth. The caller hands shortest-depth rows, and
93
+ // this keeps the guarantee local rather than trusting it.
94
+ const seen = new Set();
95
+ for (const t of list) {
96
+ const key = String(t && t.task_id);
97
+ if (!/^[1-9]\d*$/.test(key) || seen.has(key)) continue;
98
+ seen.add(key);
99
+
100
+ if (paidMap.has(key)) {
101
+ out.paid += Number(paidMap.get(key)) || 0;
102
+ out.payments += 1;
103
+ continue;
104
+ }
105
+
106
+ if (t.status !== 'shipped') continue;
107
+ const depth = Number(t.depth);
108
+ if (!Number.isInteger(depth) || depth < 0) continue;
109
+ // Depth 0 is the direct payout at full share; below that the cap applies,
110
+ // because past it even a perfect idea's decayed share rounds away.
111
+ if (depth > 0 && (rate === 0 || depth > maxDepth)) continue;
112
+ const delta = Math.round(IDEA_TASK_SHIP_BASE * factor * Math.pow(rate, depth));
113
+ if (delta <= 0) continue;
114
+ out.estimated += delta;
115
+ out.estimatedPayments += 1;
116
+ }
117
+ return out;
118
+ }
119
+
120
+ // descentRowsFromTrail — the tasks under an idea, as the TRAIL already holds
121
+ // them. Pure, and deliberately not a walk.
122
+ //
123
+ // modules/ideas/trail-descent.js has already walked the whole page by the time
124
+ // size is attached (the route composes them in that order), so the trail path
125
+ // re-uses that result and costs no extra round trip at all. `lineage_tasks` are
126
+ // the idea's own tasks — depth 0, the full-share hop — and `descent_tasks` are
127
+ // everything below them, already carrying their shortest depth and their status.
128
+ //
129
+ // A lineage row that also appears in the descent is dropped by the depth-0 entry
130
+ // winning: the Set in priceDescentForIdea keeps the first sighting, and the
131
+ // direct tasks are emitted first for exactly that reason.
132
+ function descentRowsFromTrail(idea) {
133
+ const rows = [];
134
+ const direct = Array.isArray(idea && idea.lineage_tasks) ? idea.lineage_tasks : [];
135
+ for (const t of direct) rows.push({ task_id: t.task_id, depth: 0, status: t.status });
136
+ // The legacy single-FK promotion, for rows that predate ideas_task_lineage —
137
+ // the same fallback the trail and trail-descent both apply.
138
+ if (direct.length === 0 && idea && idea.promoted_to_task_id != null) {
139
+ rows.push({ task_id: idea.promoted_to_task_id, depth: 0, status: idea.promoted_task_status ?? null });
140
+ }
141
+ const below = Array.isArray(idea && idea.descent_tasks) ? idea.descent_tasks : [];
142
+ for (const t of below) rows.push({ task_id: t.task_id, depth: t.depth, status: t.status });
143
+ return rows;
144
+ }
145
+
146
+ module.exports = {
147
+ priceDescentForIdea,
148
+ descentRowsFromTrail,
149
+ };