@bongos/core 1.24.10 → 1.24.11

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.
Files changed (33) hide show
  1. package/.bongos-core.json +55 -35
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +6 -0
  4. package/clients/bongos-client/index.cjs +6 -0
  5. package/clients/bongos-client/index.d.ts +10 -1
  6. package/clients/bongos-client/index.mjs +6 -0
  7. package/docs/api/openapi.json +132 -5
  8. package/docs/api-reference.md +10 -3
  9. package/docs/architecture.md +4 -0
  10. package/docs/copy-inventory.md +65 -59
  11. package/docs/copy-registry.json +123 -69
  12. package/docs/module-api-changelog.md +2 -0
  13. package/docs/page-readings.json +33 -33
  14. package/modules/government/decision-rules.js +1 -0
  15. package/modules/hall-ui/public/project-settings.css +12 -0
  16. package/modules/hall-ui/public/project-settings.js +63 -1
  17. package/modules/hall-ui/public/task.js +34 -1
  18. package/modules/lifecycle/migrations/lifecycle_018_pay_terms.sql +64 -0
  19. package/modules/lifecycle/pay-terms.js +171 -0
  20. package/modules/lifecycle/routes/project-settings.js +94 -0
  21. package/modules/lifecycle/routes/task-write-routes.js +35 -4
  22. package/package-lock.json +2 -2
  23. package/package.json +1 -1
  24. package/release-notes.json +6 -0
  25. package/scripts/bongos/government-walk.js +1 -0
  26. package/scripts/bongos/run-unit-tests.js +4 -0
  27. package/scripts/bongos/start.js +42 -2
  28. package/src/module-api.js +1 -1
  29. package/tests/government_act_alone_buildings.mjs +1 -0
  30. package/tests/patch_gate_ordering.mjs +3 -0
  31. package/tests/pay_terms.mjs +254 -0
  32. package/tests/pay_terms_db.mjs +86 -0
  33. package/tests/project_settings_page.mjs +25 -6
@@ -595,20 +595,20 @@
595
595
  "surface": "builders",
596
596
  "title": "Deploy",
597
597
  "states_read": ["work","out"],
598
- "files_hash": "837d73552bebd975",
598
+ "files_hash": "aae8d17481705b5a",
599
599
  "reading_hash": "b9b3d3cdbfae00be",
600
600
  "counts": {"lines":17,"placed":5,"shared":8,"unplaced":4},
601
601
  "omitted": {"data":3},
602
602
  "notes": [],
603
603
  "lines": [
604
- {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":871,"string_id":"87cee78ca134"},
604
+ {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
605
605
  {"key":"L0002","section":"top bar","text":"Deploy","placement":"shared"},
606
- {"key":"L0003","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":543,"string_id":"eba610d25523"},
606
+ {"key":"L0003","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":540,"string_id":"eba610d25523"},
607
607
  {"key":"L0004","section":"top bar","text":"Ctrl K","placement":"shared"},
608
608
  {"key":"L0005","section":"top bar","text":"Building","placement":"shared"},
609
609
  {"key":"L0006","section":"top bar","text":"Artistry","placement":"shared"},
610
610
  {"key":"L0007","section":"top bar","text":"Ideating","placement":"shared"},
611
- {"key":"L0008","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":519,"string_id":"1883ad7f07fc"},
611
+ {"key":"L0008","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":516,"string_id":"1883ad7f07fc"},
612
612
  {"key":"L0009","section":"page top","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
613
613
  {"key":"L0010","section":"What are you doing now?","text":"What are you doing now?","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":671,"string_id":"60853319f290"},
614
614
  {"key":"L0011","section":"What are you doing now?","text":"Pick one. You can switch any time from the top bar.","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":672,"string_id":"4f87d5b17b54"},
@@ -1114,15 +1114,15 @@
1114
1114
  "surface": "builders",
1115
1115
  "title": "Fleet costs",
1116
1116
  "states_read": ["ledger","out"],
1117
- "files_hash": "f344b03101ba3915",
1117
+ "files_hash": "eaa942c16882232e",
1118
1118
  "reading_hash": "382e521aaa529c82",
1119
1119
  "counts": {"lines":32,"placed":9,"shared":8,"unplaced":15},
1120
1120
  "omitted": {"data":13},
1121
1121
  "notes": [],
1122
1122
  "lines": [
1123
- {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":871,"string_id":"87cee78ca134"},
1123
+ {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
1124
1124
  {"key":"L0002","section":"top bar","text":"Fleet costs","placement":"shared","file":"modules/hall-ui/public/fleet.html","line":15,"string_id":"e0e2606e1104"},
1125
- {"key":"L0003","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":543,"string_id":"eba610d25523"},
1125
+ {"key":"L0003","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":540,"string_id":"eba610d25523"},
1126
1126
  {"key":"L0004","section":"top bar","text":"Ctrl K","placement":"shared"},
1127
1127
  {"key":"L0005","section":"top bar","text":"Building","placement":"shared"},
1128
1128
  {"key":"L0006","section":"top bar","text":"Artistry","placement":"shared"},
@@ -1142,7 +1142,7 @@
1142
1142
  {"key":"L0020","section":"What each project costs","text":"not visible to us","placement":"unplaced"},
1143
1143
  {"key":"L0021","section":"What each project costs","text":"Total","placement":"unplaced"},
1144
1144
  {"key":"L0022","section":"What each project costs","text":"+ 2 not priced, 1 not visible","placement":"unplaced"},
1145
- {"key":"L0023","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":519,"string_id":"1883ad7f07fc"},
1145
+ {"key":"L0023","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":516,"string_id":"1883ad7f07fc"},
1146
1146
  {"key":"L0024","section":"What each project costs","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
1147
1147
  {"key":"L0025","section":"What are you doing now?","text":"What are you doing now?","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":671,"string_id":"60853319f290"},
1148
1148
  {"key":"L0026","section":"What are you doing now?","text":"Pick one. You can switch any time from the top bar.","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":672,"string_id":"4f87d5b17b54"},
@@ -2712,15 +2712,15 @@
2712
2712
  "surface": "builders",
2713
2713
  "title": "Project settings",
2714
2714
  "states_read": ["default"],
2715
- "files_hash": "5c7e885ac6ee64a0",
2715
+ "files_hash": "0ab855a440ebe957",
2716
2716
  "reading_hash": "4f7a29f2c2f0ad7c",
2717
2717
  "counts": {"lines":38,"placed":20,"shared":8,"unplaced":10},
2718
2718
  "omitted": {"data":31},
2719
2719
  "notes": [],
2720
2720
  "lines": [
2721
- {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":871,"string_id":"87cee78ca134"},
2721
+ {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
2722
2722
  {"key":"L0002","section":"top bar","text":"Project settings","placement":"shared","file":"modules/hall-ui/public/project-settings.html","line":15,"string_id":"e08628967f2f"},
2723
- {"key":"L0003","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":543,"string_id":"eba610d25523"},
2723
+ {"key":"L0003","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":540,"string_id":"eba610d25523"},
2724
2724
  {"key":"L0004","section":"top bar","text":"Ctrl K","placement":"shared"},
2725
2725
  {"key":"L0005","section":"top bar","text":"Building","placement":"shared"},
2726
2726
  {"key":"L0006","section":"top bar","text":"Artistry","placement":"shared"},
@@ -2740,13 +2740,13 @@
2740
2740
  {"key":"L0020","section":"The fundamentals","text":"not yet real","placement":"unplaced"},
2741
2741
  {"key":"L0021","section":"The fundamentals","text":"not available ({…})","placement":"unplaced"},
2742
2742
  {"key":"L0022","section":"Danger zone","text":"Danger zone","placement":"placed","file":"modules/hall-ui/public/project-settings.html","line":56,"string_id":"13b22e48d9fb"},
2743
- {"key":"L0023","section":"Danger zone","text":"This project is hosted on {…}, and that is where it is taken offline or removed. Both links below open this project’s page there.","placement":"placed","file":"modules/hall-ui/public/project-settings.js","line":350,"string_id":"e97b2d549f10"},
2744
- {"key":"L0024","section":"Danger zone","text":"Manage this project on {…}","placement":"placed","file":"modules/hall-ui/public/project-settings.js","line":351,"string_id":"4e261fd15bd5"},
2743
+ {"key":"L0023","section":"Danger zone","text":"This project is hosted on {…}, and that is where it is taken offline or removed. Both links below open this project’s page there.","placement":"placed","file":"modules/hall-ui/public/project-settings.js","line":412,"string_id":"e97b2d549f10"},
2744
+ {"key":"L0024","section":"Danger zone","text":"Manage this project on {…}","placement":"placed","file":"modules/hall-ui/public/project-settings.js","line":413,"string_id":"4e261fd15bd5"},
2745
2745
  {"key":"L0025","section":"Danger zone","text":"Take it offline","placement":"placed","file":"modules/hall-ui/public/project-settings.html","line":59,"string_id":"da9da6e866bd"},
2746
2746
  {"key":"L0026","section":"Danger zone","text":"— stops the project and its nightly backups but keeps everything: its database, its backups and your repository on GitHub. You can bring it back.","placement":"placed","file":"modules/hall-ui/public/project-settings.html","line":59,"string_id":"61ebc5d684fd"},
2747
2747
  {"key":"L0027","section":"Danger zone","text":"Disconnect from Bongos entirely","placement":"placed","file":"modules/hall-ui/public/project-settings.html","line":60,"string_id":"d3efd513694b"},
2748
2748
  {"key":"L0028","section":"Danger zone","text":"— erases the project’s server, its database and every backup, and releases its name and web address. Your repository on GitHub is kept. This cannot be undone.","placement":"placed","file":"modules/hall-ui/public/project-settings.html","line":60,"string_id":"d9ad3ee37a88"},
2749
- {"key":"L0029","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":519,"string_id":"1883ad7f07fc"},
2749
+ {"key":"L0029","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":516,"string_id":"1883ad7f07fc"},
2750
2750
  {"key":"L0030","section":"Danger zone","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
2751
2751
  {"key":"L0031","section":"What are you doing now?","text":"What are you doing now?","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":671,"string_id":"60853319f290"},
2752
2752
  {"key":"L0032","section":"What are you doing now?","text":"Pick one. You can switch any time from the top bar.","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":672,"string_id":"4f87d5b17b54"},
@@ -4194,29 +4194,29 @@
4194
4194
  "surface": "builders",
4195
4195
  "title": "Task",
4196
4196
  "states_read": ["record","from-goal","missing"],
4197
- "files_hash": "5848634958d25591",
4197
+ "files_hash": "fc66f478feb124ed",
4198
4198
  "reading_hash": "7ce8be5d967d835b",
4199
4199
  "counts": {"lines":149,"placed":43,"shared":10,"unplaced":96},
4200
4200
  "omitted": {"data":109},
4201
4201
  "notes": [],
4202
4202
  "lines": [
4203
- {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":871,"string_id":"87cee78ca134"},
4203
+ {"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
4204
4204
  {"key":"L0002","section":"top bar","text":"goal 1000081","placement":"shared","state":"from-goal"},
4205
4205
  {"key":"L0003","section":"top bar","text":"Tasks","placement":"shared"},
4206
- {"key":"L0004","section":"top bar","text":"Task","placement":"shared","file":"modules/hall-ui/public/task.js","line":491,"string_id":"eff70e59d12e"},
4207
- {"key":"L0005","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":543,"string_id":"eba610d25523"},
4206
+ {"key":"L0004","section":"top bar","text":"Task","placement":"shared","file":"modules/hall-ui/public/task.js","line":512,"string_id":"eff70e59d12e"},
4207
+ {"key":"L0005","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":540,"string_id":"eba610d25523"},
4208
4208
  {"key":"L0006","section":"top bar","text":"Ctrl K","placement":"shared"},
4209
4209
  {"key":"L0007","section":"top bar","text":"Building","placement":"shared"},
4210
4210
  {"key":"L0008","section":"top bar","text":"Artistry","placement":"shared"},
4211
4211
  {"key":"L0009","section":"top bar","text":"Ideating","placement":"shared"},
4212
- {"key":"L0010","section":"page top","text":"Task {…}","placement":"placed","file":"modules/hall-ui/public/task.js","line":491,"string_id":"eff70e59d12e"},
4213
- {"key":"L0011","section":"page top","text":"Task","placement":"placed","file":"modules/hall-ui/public/task.js","line":491,"string_id":"eff70e59d12e"},
4212
+ {"key":"L0010","section":"page top","text":"Task {…}","placement":"placed","file":"modules/hall-ui/public/task.js","line":512,"string_id":"eff70e59d12e"},
4213
+ {"key":"L0011","section":"page top","text":"Task","placement":"placed","file":"modules/hall-ui/public/task.js","line":512,"string_id":"eff70e59d12e"},
4214
4214
  {"key":"L0012","section":"page top","text":"shipped","placement":"placed","file":"modules/hall-ui/public/goals-render.js","line":821,"string_id":"bd3402efa59e"},
4215
4215
  {"key":"L0013","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"· {…} · {…} · {…} to any rank","placement":"unplaced"},
4216
4216
  {"key":"L0014","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Created {…}, 78d ago.","placement":"unplaced"},
4217
4217
  {"key":"L0015","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Goal","placement":"placed","file":"modules/hall-ui/public/gate.js","line":194,"string_id":"ec88b946ad16"},
4218
4218
  {"key":"L0016","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":12},
4219
- {"key":"L0017","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Move to goal","placement":"placed","file":"modules/hall-ui/public/task.js","line":578,"string_id":"e52ae74f0052"},
4219
+ {"key":"L0017","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Move to goal","placement":"placed","file":"modules/hall-ui/public/task.js","line":599,"string_id":"e52ae74f0052"},
4220
4220
  {"key":"L0018","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","occurrences":2},
4221
4221
  {"key":"L0019","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Move","placement":"unplaced"},
4222
4222
  {"key":"L0020","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Priority","placement":"unplaced","occurrences":2},
@@ -4226,11 +4226,11 @@
4226
4226
  {"key":"L0024","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"P3","placement":"unplaced"},
4227
4227
  {"key":"L0025","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"P4","placement":"unplaced"},
4228
4228
  {"key":"L0026","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"P5","placement":"unplaced"},
4229
- {"key":"L0027","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Wait for task","placement":"placed","file":"modules/hall-ui/public/task.js","line":608,"string_id":"411b2ff58094"},
4230
- {"key":"L0028","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"task id","placement":"placed","file":"modules/hall-ui/public/task.js","line":608,"string_id":"3906fbc07bbe","attr":"placeholder"},
4231
- {"key":"L0029","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Set priority","placement":"placed","file":"modules/hall-ui/public/task.js","line":608,"string_id":"c11213056bab"},
4232
- {"key":"L0030","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Add dependency","placement":"placed","file":"modules/hall-ui/public/task.js","line":608,"string_id":"2b94171ce525"},
4233
- {"key":"L0031","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"A dependency keeps this task out of the claimable queue until that one ships. Remove one with the × beside it under “Blocked by”.","placement":"placed","file":"modules/hall-ui/public/task.js","line":608,"string_id":"518e5acc9184"},
4229
+ {"key":"L0027","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Wait for task","placement":"placed","file":"modules/hall-ui/public/task.js","line":629,"string_id":"411b2ff58094"},
4230
+ {"key":"L0028","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"task id","placement":"placed","file":"modules/hall-ui/public/task.js","line":629,"string_id":"3906fbc07bbe","attr":"placeholder"},
4231
+ {"key":"L0029","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Set priority","placement":"placed","file":"modules/hall-ui/public/task.js","line":629,"string_id":"c11213056bab"},
4232
+ {"key":"L0030","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Add dependency","placement":"placed","file":"modules/hall-ui/public/task.js","line":629,"string_id":"2b94171ce525"},
4233
+ {"key":"L0031","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"A dependency keeps this task out of the claimable queue until that one ships. Remove one with the × beside it under “Blocked by”.","placement":"placed","file":"modules/hall-ui/public/task.js","line":629,"string_id":"518e5acc9184"},
4234
4234
  {"key":"L0032","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Estimated","placement":"unplaced"},
4235
4235
  {"key":"L0033","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"m","placement":"unplaced","occurrences":2},
4236
4236
  {"key":"L0034","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Actual","placement":"unplaced"},
@@ -4244,7 +4244,7 @@
4244
4244
  {"key":"L0042","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Credit","placement":"unplaced"},
4245
4245
  {"key":"L0043","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"80 {…} landed","placement":"unplaced"},
4246
4246
  {"key":"L0044","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"2 claims","placement":"unplaced"},
4247
- {"key":"L0045","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Last claimed by","placement":"placed","file":"modules/hall-ui/public/task.js","line":658,"string_id":"13bae4dfb28e"},
4247
+ {"key":"L0045","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Last claimed by","placement":"placed","file":"modules/hall-ui/public/task.js","line":683,"string_id":"13bae4dfb28e"},
4248
4248
  {"key":"L0046","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"on {…}, {…} released, outcome {…}.","placement":"unplaced"},
4249
4249
  {"key":"L0047","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Value","placement":"unplaced"},
4250
4250
  {"key":"L0048","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Description","placement":"unplaced"},
@@ -4301,8 +4301,8 @@
4301
4301
  {"key":"L0099","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Touches","placement":"unplaced"},
4302
4302
  {"key":"L0100","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"3 files","placement":"unplaced"},
4303
4303
  {"key":"L0101","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Blocks","placement":"unplaced"},
4304
- {"key":"L0102","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Shipped","placement":"placed","file":"modules/hall-ui/public/task.js","line":693,"string_id":"0c0a50ba1666"},
4305
- {"key":"L0103","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Shipped {…}{…}, {…}.","placement":"placed","file":"modules/hall-ui/public/task.js","line":693,"string_id":"0c0a50ba1666"},
4304
+ {"key":"L0102","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Shipped","placement":"placed","file":"modules/hall-ui/public/task.js","line":718,"string_id":"0c0a50ba1666"},
4305
+ {"key":"L0103","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"Shipped {…}{…}, {…}.","placement":"placed","file":"modules/hall-ui/public/task.js","line":718,"string_id":"0c0a50ba1666"},
4306
4306
  {"key":"L0104","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"The adversarial panel. Each worker reports pass, concerns or fail on its own; the gating workers must all pass before confirmed becomes {…}, and one concerns falls the task through to the manual confirm path.","placement":"placed","file":"modules/hall-ui/public/task.js","line":428,"string_id":"6e93ef49d63f"},
4307
4307
  {"key":"L0105","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"verdict {…}","placement":"placed","file":"modules/hall-ui/public/task.js","line":432,"string_id":"4de556377db2"},
4308
4308
  {"key":"L0106","section":"2166hall-kit.js: shared hall UI primitives (pager, ledger, filter bar, tabs, ra…","text":"threshold 6 · panel {…} · {…}","placement":"unplaced"},
@@ -4334,12 +4334,12 @@
4334
4334
  {"key":"L0132","section":"Open {…}","text":"Sort it for me","placement":"placed","file":"modules/hall-ui/public/notes-panel.js","line":68,"string_id":"cf3966c3039f"},
4335
4335
  {"key":"L0133","section":"Open {…}","text":"Add note","placement":"placed","file":"modules/hall-ui/public/notes-panel.js","line":68,"string_id":"61bfb27cd26f"},
4336
4336
  {"key":"L0134","section":"Open {…}","text":"Actions","placement":"unplaced"},
4337
- {"key":"L0135","section":"Open {…}","text":"Shipped. Credits paid.","placement":"placed","file":"modules/hall-ui/public/task.js","line":744,"string_id":"d5d2c063b814"},
4338
- {"key":"L0136","section":"Open {…}","text":"Copy prompt","placement":"placed","file":"modules/hall-ui/public/task.js","line":823,"string_id":"a873e7c29d80"},
4337
+ {"key":"L0135","section":"Open {…}","text":"Shipped. Credits paid.","placement":"placed","file":"modules/hall-ui/public/task.js","line":769,"string_id":"d5d2c063b814"},
4338
+ {"key":"L0136","section":"Open {…}","text":"Copy prompt","placement":"placed","file":"modules/hall-ui/public/task.js","line":848,"string_id":"a873e7c29d80"},
4339
4339
  {"key":"L0137","section":"Open {…}","text":"Back to goal 1000081","placement":"unplaced","state":"from-goal"},
4340
4340
  {"key":"L0138","section":"Open {…}","text":"Back to tasks","placement":"placed","file":"modules/hall-ui/public/task.js","line":208,"string_id":"ef2fab4901d6"},
4341
- {"key":"L0139","section":"Open {…}","text":"A shipped task cannot be retired — it is immutable history now.","placement":"placed","file":"modules/hall-ui/public/task.js","line":776,"string_id":"f3d6ed7c0d2c"},
4342
- {"key":"L0140","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":519,"string_id":"1883ad7f07fc"},
4341
+ {"key":"L0139","section":"Open {…}","text":"A shipped task cannot be retired — it is immutable history now.","placement":"placed","file":"modules/hall-ui/public/task.js","line":801,"string_id":"f3d6ed7c0d2c"},
4342
+ {"key":"L0140","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":516,"string_id":"1883ad7f07fc"},
4343
4343
  {"key":"L0141","section":"Open {…}","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
4344
4344
  {"key":"L0142","section":"What are you doing now?","text":"What are you doing now?","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":671,"string_id":"60853319f290"},
4345
4345
  {"key":"L0143","section":"What are you doing now?","text":"Pick one. You can switch any time from the top bar.","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":672,"string_id":"4f87d5b17b54"},
@@ -67,6 +67,7 @@ const AREAS = Object.freeze([
67
67
  'PATCH /project-settings/rot-days',
68
68
  'PATCH /project-settings/ship-mode',
69
69
  'PATCH /project-settings/tweak-autopickup',
70
+ 'PATCH /project-settings/pay-terms', // task 1004990: the project's standing pay terms
70
71
  'PATCH /work-categories/:id',
71
72
  // task 1004941: the owner approving a Market Watch proposal (a passed
72
73
  // matter approves it through the market_watch_proposal act instead)
@@ -60,6 +60,18 @@
60
60
  border-top: var(--line) solid var(--rule-soft);
61
61
  }
62
62
  .ps-cat--off { opacity: 0.6; }
63
+
64
+ /* Pay terms (task 1004990): one wrapping line per term, the category list's shape. */
65
+ .ps-pays { margin: 10px 0 0; padding: 0; list-style: none; }
66
+ .ps-pay {
67
+ display: flex;
68
+ flex-wrap: wrap;
69
+ align-items: center;
70
+ gap: 8px;
71
+ padding: 8px 0;
72
+ border-top: var(--line) solid var(--rule-soft);
73
+ }
74
+ .ps-pay__note { flex: 1 1 200px; min-width: 0; }
63
75
  .ps-cat__slug {
64
76
  font-size: 11px;
65
77
  color: var(--ink-soft);
@@ -198,6 +198,44 @@
198
198
  </div>`;
199
199
  }
200
200
 
201
+ // Pay terms (task 1004990, ADR 0385 decision 3): the project's standing pay, in
202
+ // its own words. One line per term plus a blank one to add; picking "remove"
203
+ // drops a line. Every box starts EMPTY on a new line — Bongos suggests no amount.
204
+ // The history under it is the audit trail: who changed the terms, and when.
205
+ function payTermLineHtml(types, t) {
206
+ const opts = [`<option value="">${t ? 'remove' : 'add a term…'}</option>`]
207
+ .concat(types.map((o) => `<option value="${escapeHtml(o.type)}" ${t && t.pay_type === o.type ? 'selected' : ''}>${escapeHtml(o.label)}</option>`));
208
+ const val = (f) => escapeHtml(t && t[f] != null ? String(t[f]) : '');
209
+ return `
210
+ <li class="ps-pay">
211
+ <select class="ps-pay__type" aria-label="Kind of pay">${opts.join('')}</select>
212
+ <input type="text" class="ps-pay__amount" maxlength="64" value="${val('amount')}" placeholder="amount, as you state it" aria-label="Amount">
213
+ <input type="text" class="ps-pay__unit" maxlength="32" value="${val('unit')}" placeholder="unit" aria-label="Unit">
214
+ <input type="text" class="ps-pay__note" maxlength="500" value="${val('note')}" placeholder="note" aria-label="Note">
215
+ </li>`;
216
+ }
217
+
218
+ function payTermsBodyHtml(row) {
219
+ const v = row.value || {};
220
+ const types = Array.isArray(v.types) ? v.types : [];
221
+ const terms = Array.isArray(v.terms) ? v.terms : [];
222
+ const lines = terms.map((t) => payTermLineHtml(types, t));
223
+ if (terms.length < (v.max || 10)) lines.push(payTermLineHtml(types, null));
224
+ const selfManaged = terms.some((t) => t.pay_type === 'self_managed')
225
+ ? `<p class="ps-sibling">${escapeHtml(String(v.self_managed_label || ''))}</p>` : '';
226
+ const history = (Array.isArray(v.history) ? v.history : []).map((h) => `
227
+ <li>${escapeHtml(h.set_by_login ? '@' + h.set_by_login : 'builder ' + h.set_by)} set
228
+ ${escapeHtml(String(h.terms.length))} term${h.terms.length === 1 ? '' : 's'}
229
+ on ${escapeHtml(new Date(h.set_at).toLocaleString())}</li>`).join('');
230
+ return `
231
+ <ul class="ps-pays">${lines.join('')}</ul>
232
+ ${selfManaged}
233
+ <div class="ps-controls">
234
+ <button type="button" class="btn" id="ps-pay-save">Save pay terms</button>
235
+ </div>
236
+ ${history ? `<details class="ps-sibling"><summary>Who changed the pay terms</summary><ul>${history}</ul></details>` : ''}`;
237
+ }
238
+
201
239
  // ---- render + wire -------------------------------------------------------
202
240
 
203
241
  let rows = [];
@@ -209,6 +247,7 @@
209
247
  if (row.key === 'tweak_round_cap' && row.editable) return rowHtml(row, tweakCapBodyHtml(row));
210
248
  if (row.key === 'rot_timer' && row.editable) return rowHtml(row, rotBodyHtml(row));
211
249
  if (row.key === 'work_categories' && row.editable) return rowHtml(row, catsBodyHtml(row));
250
+ if (row.key === 'pay_terms' && row.editable) return rowHtml(row, payTermsBodyHtml(row));
212
251
  return rowHtml(row, '');
213
252
  }).join('')}</ul>`;
214
253
  wire();
@@ -219,10 +258,33 @@
219
258
  // reply, arriving first, can repaint a value nobody asked for.
220
259
  function setBusy(on) {
221
260
  const mount = $('ps-rows');
222
- mount.querySelectorAll('input, button').forEach((el) => { el.disabled = on; });
261
+ mount.querySelectorAll('input, button, select').forEach((el) => { el.disabled = on; });
223
262
  }
224
263
 
225
264
  function wire() {
265
+ const paySave = $('ps-pay-save');
266
+ if (paySave) {
267
+ paySave.addEventListener('click', async () => {
268
+ // Only what was typed is sent; an empty box stays empty (null), never filled.
269
+ const terms = [];
270
+ document.querySelectorAll('.ps-pay').forEach((li) => {
271
+ const type = li.querySelector('.ps-pay__type').value;
272
+ if (!type) return;
273
+ const text = (cls) => { const s = String(li.querySelector(cls).value || '').trim(); return s || null; };
274
+ terms.push({ pay_type: type, amount: text('.ps-pay__amount'), unit: text('.ps-pay__unit'), note: text('.ps-pay__note') });
275
+ });
276
+ setBusy(true);
277
+ try {
278
+ await sendJson('PATCH', '/project-settings/pay-terms', { terms });
279
+ toast(terms.length ? 'Pay terms saved.' : 'Pay terms cleared.');
280
+ await load();
281
+ } catch (err) {
282
+ toast(err.message || 'Could not save the pay terms.');
283
+ setBusy(false);
284
+ }
285
+ });
286
+ }
287
+
226
288
  const shipSave = $('ps-ship-save');
227
289
  if (shipSave) {
228
290
  shipSave.addEventListener('click', async () => {
@@ -484,8 +484,29 @@
484
484
  return `<section class="rec-sec" id="task-sessions"><p class="rec-sec__h">Session log${count}</p>${blocks.join('')}</section>`;
485
485
  }
486
486
 
487
+ // The task's pay terms as the project stated them (task 1004990). Amounts are the
488
+ // project's text, shown verbatim — never a figure Bongos computed or suggested,
489
+ // and never a balance. A missing amount reads "not stated". A self-managed term
490
+ // carries the server's label saying Bongos moves and guarantees none of it.
491
+ // Terms that come from the project's standing policy say so. Nothing to show
492
+ // (none stated anywhere) draws nothing.
493
+ function payTermsHtml(view) {
494
+ if (!view || !Array.isArray(view.terms) || !view.terms.length) return '';
495
+ const lines = view.terms.map((term) => {
496
+ const amount = term.amount
497
+ ? `${escapeHtml(term.amount)}${term.unit ? ' ' + escapeHtml(term.unit) : ''}`
498
+ : '<em>amount not stated</em>';
499
+ return `<li><strong>${escapeHtml(term.type_label || term.pay_type)}</strong> — ${amount}`
500
+ + (term.note ? `<br>${escapeHtml(term.note)}` : '')
501
+ + (term.label ? `<br><em>${escapeHtml(term.label)}</em>` : '')
502
+ + '</li>';
503
+ }).join('');
504
+ const from = view.source === 'project' ? ' <em>this project’s standing terms</em>' : '';
505
+ return `<section class="rec-sec" id="task-pay"><p class="rec-sec__h">Pay${from}</p><ul>${lines}</ul></section>`;
506
+ }
507
+
487
508
  function renderTask(t, lastClaim, viewer, goal, extras) {
488
- const { grade = null, sessionLogs = null, claims = null, goalsList = null } = extras || {};
509
+ const { grade = null, sessionLogs = null, claims = null, goalsList = null, payTerms = null } = extras || {};
489
510
  document.title = `#${t.id} — ${t.title || 'Task'} — ${document.title.split(' — ').pop()}`;
490
511
  const sub = $('#task-sub');
491
512
  if (sub) sub.textContent = `Task ${t.id}`;
@@ -631,6 +652,10 @@
631
652
  ['Priority', t.priority == null ? null : 'P' + t.priority],
632
653
  ]));
633
654
  parts.push(lifecycleRail(t, creditVal));
655
+ // What the task pays, in the PROJECT's words (task 1004990, ADR 0385 D3), drawn
656
+ // beside the Claim button so a builder reads it before claiming.
657
+ const pay = payTermsHtml(payTerms);
658
+ if (pay) parts.push(pay);
634
659
  // A slot a MODULE may fill (task 1004301): the module's public/task-widget.js is
635
660
  // injected just before this script and writes into it on `otb:task-shown` below. The
636
661
  // page itself names no module and draws nothing here — with none enabled it stays
@@ -1086,10 +1111,18 @@
1086
1111
  if (ri && typeof ri.blob_base === 'string') repoBlobBase = ri.blob_base;
1087
1112
  if (ri && typeof ri.tree_base === 'string') repoTreeBase = ri.tree_base;
1088
1113
  } catch (_) { /* links degrade to the original href */ }
1114
+ // task 1004990: the task's pay terms, in the project's words. Best-effort: an
1115
+ // older server without the read draws no pay section rather than no page.
1116
+ let payTerms = null;
1117
+ try {
1118
+ const pt = await getJSON(`${API}/pay-terms?task_ids=${encodeURIComponent(d.task.id)}`, { softAuth: true });
1119
+ payTerms = (pt && pt.pay_terms && pt.pay_terms[String(d.task.id)]) || null;
1120
+ } catch (_) { /* no pay section */ }
1089
1121
  renderTask(d.task, d.last_claim || null, viewer, goal, {
1090
1122
  grade: d.grade || null,
1091
1123
  sessionLogs: Array.isArray(d.session_logs) ? d.session_logs : null,
1092
1124
  claims: Array.isArray(d.claims) ? d.claims : null,
1125
+ payTerms,
1093
1126
  goalsList,
1094
1127
  });
1095
1128
  } catch (err) {
@@ -0,0 +1,64 @@
1
+ -- lifecycle_018_pay_terms.sql — task 1004990 (goal 1000092; ADR 0385 decision 3
2
+ -- and its 2026-10-29 amendment).
3
+ --
4
+ -- The PROJECT sets the pay, not Bongos. A task can carry zero or more pay terms,
5
+ -- each in the project's own words: a type, an amount and a unit as the project
6
+ -- states them, and a note. A project can also keep standing pay terms that apply
7
+ -- to every task without terms of its own — that is the project's pay policy,
8
+ -- and per the owner's ruling it lives here, in the database, changed on the
9
+ -- project's settings page, never in the branding pack.
10
+ --
11
+ -- A LIFECYCLE MIGRATION, NOT A CORE ONE: these are brand-new tables the lifecycle
12
+ -- module owns (modules/lifecycle/pay-terms.js is their only reader and writer), so
13
+ -- they are lifecycle_-namespaced here, the lifecycle_017_notes precedent — a core
14
+ -- migration is only for a change to a core table.
15
+ --
16
+ -- RECORDS ONLY. Nothing here moves, holds, owes or guarantees money; the amount
17
+ -- is TEXT on purpose, so no code can sum it into a balance (ADR 0387: money stays
18
+ -- with the processor). Bongos suggests no amount: no column has a default.
19
+ --
20
+ -- THE SHAPE IS A HISTORY OF WHOLE SETS. Each change appends one set row (who,
21
+ -- when, which task — NULL for the project's standing terms) and the terms that
22
+ -- set holds. The newest set is current; a set with no terms means "no pay terms".
23
+ -- So the audit trail of who changed what and when is the table itself, and
24
+ -- nothing is ever edited or deleted: a row trigger refuses UPDATE and DELETE on
25
+ -- both tables. (A whole-table wipe is not guarded here: the module-migration gate
26
+ -- keeps module migrations additive and refuses that statement's keyword outright,
27
+ -- and no code path in the tree issues one.)
28
+
29
+ CREATE TABLE IF NOT EXISTS lifecycle_pay_term_sets (
30
+ id bigserial PRIMARY KEY,
31
+ task_id bigint REFERENCES tasks(id), -- NULL = the project's standing terms
32
+ set_by bigint NOT NULL REFERENCES builders(id),
33
+ set_at timestamptz NOT NULL DEFAULT now()
34
+ );
35
+
36
+ -- The current set for a task (or for the project, task_id NULL): newest first.
37
+ CREATE INDEX IF NOT EXISTS lifecycle_pay_term_sets_current
38
+ ON lifecycle_pay_term_sets (task_id, set_at DESC, id DESC);
39
+
40
+ CREATE TABLE IF NOT EXISTS lifecycle_pay_terms (
41
+ id bigserial PRIMARY KEY,
42
+ set_id bigint NOT NULL REFERENCES lifecycle_pay_term_sets(id),
43
+ position smallint NOT NULL CHECK (position BETWEEN 0 AND 9),
44
+ pay_type text NOT NULL CHECK (pay_type IN
45
+ ('cash', 'equity', 'module_share', 'credit_pool', 'non_monetary', 'self_managed')),
46
+ amount text CHECK (amount IS NULL OR char_length(amount) BETWEEN 1 AND 64),
47
+ unit text CHECK (unit IS NULL OR char_length(unit) BETWEEN 1 AND 32),
48
+ note text CHECK (note IS NULL OR char_length(note) BETWEEN 1 AND 500),
49
+ UNIQUE (set_id, position)
50
+ );
51
+
52
+ CREATE OR REPLACE FUNCTION lifecycle_pay_terms_refuse_change() RETURNS trigger AS $$
53
+ BEGIN
54
+ RAISE EXCEPTION 'pay terms are a history: % on % is refused; set a new set of terms instead', TG_OP, TG_TABLE_NAME
55
+ USING ERRCODE = 'check_violation';
56
+ END;
57
+ $$ LANGUAGE plpgsql;
58
+
59
+ DROP TRIGGER IF EXISTS lifecycle_pay_term_sets_append_only ON lifecycle_pay_term_sets;
60
+ CREATE TRIGGER lifecycle_pay_term_sets_append_only BEFORE UPDATE OR DELETE ON lifecycle_pay_term_sets
61
+ FOR EACH ROW EXECUTE FUNCTION lifecycle_pay_terms_refuse_change();
62
+ DROP TRIGGER IF EXISTS lifecycle_pay_terms_append_only ON lifecycle_pay_terms;
63
+ CREATE TRIGGER lifecycle_pay_terms_append_only BEFORE UPDATE OR DELETE ON lifecycle_pay_terms
64
+ FOR EACH ROW EXECUTE FUNCTION lifecycle_pay_terms_refuse_change();