@bongos/core 1.21.145 → 1.21.146

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 (55) hide show
  1. package/.bongos-core.json +69 -59
  2. package/clients/bongos-client/index.d.ts +2 -2
  3. package/docs/api/openapi.json +8 -4
  4. package/docs/copy-inventory.md +10 -10
  5. package/docs/copy-registry.json +12 -12
  6. package/docs/module-api-changelog.md +2 -0
  7. package/docs/page-readings.json +85 -85
  8. package/modules/hall-ui/public/atlas.html +1 -1
  9. package/modules/hall-ui/public/blockers.html +1 -1
  10. package/modules/hall-ui/public/board-room.html +1 -1
  11. package/modules/hall-ui/public/city.html +1 -1
  12. package/modules/hall-ui/public/collab.html +1 -1
  13. package/modules/hall-ui/public/commands.html +1 -1
  14. package/modules/hall-ui/public/copy-desk.html +1 -1
  15. package/modules/hall-ui/public/deploy.html +1 -1
  16. package/modules/hall-ui/public/diagrams.html +1 -1
  17. package/modules/hall-ui/public/drachmae.html +1 -1
  18. package/modules/hall-ui/public/fleet.html +1 -1
  19. package/modules/hall-ui/public/gate.html +1 -1
  20. package/modules/hall-ui/public/goal-map.html +1 -1
  21. package/modules/hall-ui/public/goals.html +1 -1
  22. package/modules/hall-ui/public/government.html +1 -1
  23. package/modules/hall-ui/public/idea.html +1 -1
  24. package/modules/hall-ui/public/ideas.html +1 -1
  25. package/modules/hall-ui/public/index.html +1 -1
  26. package/modules/hall-ui/public/modules.html +1 -1
  27. package/modules/hall-ui/public/my-agents.html +1 -1
  28. package/modules/hall-ui/public/primer.html +1 -1
  29. package/modules/hall-ui/public/profile.html +1 -1
  30. package/modules/hall-ui/public/project-settings.html +1 -1
  31. package/modules/hall-ui/public/ranks.html +1 -1
  32. package/modules/hall-ui/public/roadmap.html +1 -1
  33. package/modules/hall-ui/public/roster.html +1 -1
  34. package/modules/hall-ui/public/sessions.html +1 -1
  35. package/modules/hall-ui/public/settings-software-update.js +14 -3
  36. package/modules/hall-ui/public/settings.html +2 -2
  37. package/modules/hall-ui/public/shell.js +10 -6
  38. package/modules/hall-ui/public/street.html +1 -1
  39. package/modules/hall-ui/public/studio.html +1 -1
  40. package/modules/hall-ui/public/task.html +1 -1
  41. package/modules/hall-ui/public/thinking.html +1 -1
  42. package/modules/hall-ui/public/tweak-editor.html +1 -1
  43. package/modules/hall-ui/public/watch.html +1 -1
  44. package/modules/hall-ui/public/work.html +1 -1
  45. package/package-lock.json +2 -2
  46. package/package.json +1 -1
  47. package/release-notes.json +6 -0
  48. package/scripts/gds/provision-auto-upgrade.js +30 -7
  49. package/src/bongos/routes/core-update.js +14 -2
  50. package/src/bongos/upgrade-hold.js +96 -0
  51. package/src/module-api.js +1 -1
  52. package/tests/core_auto_upgrade.mjs +64 -3
  53. package/tests/core_upgrade_owner_door.mjs +25 -2
  54. package/tests/nav_permission_atoms.mjs +3 -2
  55. package/tests/upgrade_hold.mjs +207 -0
@@ -93,7 +93,7 @@
93
93
 
94
94
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
95
95
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
96
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
96
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
97
97
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
98
98
  <script src="/builders/palette.js" defer></script>
99
99
  <script src="/builders/atlas.js?v=2026-09-02-index" defer></script>
@@ -52,7 +52,7 @@
52
52
  chrome exists before the page script runs. -->
53
53
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
54
54
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
55
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
55
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
56
56
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
57
57
  <script src="/builders/palette.js" defer></script>
58
58
  <!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
@@ -62,7 +62,7 @@
62
62
 
63
63
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
64
64
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
65
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
65
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
66
66
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
67
67
  <script src="/builders/palette.js" defer></script>
68
68
  <script src="/builders/dom-utils.js?v=2026-06-16-board"></script>
@@ -105,7 +105,7 @@
105
105
 
106
106
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
107
107
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
108
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
108
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
109
109
  <script src="/builders/palette.js" defer></script>
110
110
  <script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
111
111
  <script src="/builders/gov-feeds.js?v=2026-10-09-living3"></script>
@@ -150,7 +150,7 @@
150
150
 
151
151
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
152
152
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
153
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
153
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
154
154
  <script src="/builders/palette.js" defer></script>
155
155
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
156
156
  <script src="/builders/collab-lib.js?v=2026-09-24-archive"></script>
@@ -56,7 +56,7 @@
56
56
 
57
57
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
58
58
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
59
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
59
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
60
60
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
61
61
  <script src="/builders/palette.js" defer></script>
62
62
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -179,7 +179,7 @@
179
179
 
180
180
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
181
181
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
182
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
182
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
183
183
  <script src="/builders/palette.js" defer></script>
184
184
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
185
185
  <script src="/builders/hall-kit.js"></script>
@@ -76,7 +76,7 @@
76
76
 
77
77
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
78
78
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
79
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
79
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
80
80
  <script src="/builders/palette.js" defer></script>
81
81
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
82
82
  <script src="/builders/hall-kit.js"></script>
@@ -99,7 +99,7 @@
99
99
  time so the chrome exists before the deferred page scripts execute. -->
100
100
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
101
101
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
102
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
102
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
103
103
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
104
104
  <script src="/builders/palette.js" defer></script>
105
105
  <script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
@@ -100,7 +100,7 @@
100
100
 
101
101
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
102
102
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
103
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
103
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
104
104
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
105
105
  <script src="/builders/palette.js" defer></script>
106
106
  <script src="/builders/md-reader.js?v=2026-09-02-mdreader-2"></script>
@@ -56,7 +56,7 @@
56
56
 
57
57
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
58
58
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
59
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
59
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
60
60
  <script src="/builders/palette.js" defer></script>
61
61
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
62
62
  <script src="/builders/hall-kit.js"></script>
@@ -79,7 +79,7 @@
79
79
 
80
80
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
81
81
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
82
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
82
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
83
83
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
84
84
  <script src="/builders/palette.js" defer></script>
85
85
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -139,7 +139,7 @@
139
139
 
140
140
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
141
141
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
142
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
142
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
143
143
  <script src="/builders/palette.js" defer></script>
144
144
 
145
145
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
@@ -232,7 +232,7 @@
232
232
 
233
233
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
234
234
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
235
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
235
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
236
236
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
237
237
  <script src="/builders/palette.js" defer></script>
238
238
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -136,7 +136,7 @@
136
136
 
137
137
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
138
138
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
139
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
139
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
140
140
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
141
141
  <script src="/builders/palette.js" defer></script>
142
142
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -52,7 +52,7 @@
52
52
 
53
53
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
54
54
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
55
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
55
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
56
56
  <script src="/builders/palette.js" defer></script>
57
57
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib" defer></script>
58
58
  <!-- task-detail.js still owns the #/idea/N and #/blocker/N overlay, so a ref
@@ -227,7 +227,7 @@
227
227
 
228
228
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
229
229
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
230
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
230
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
231
231
  <script src="/builders/palette.js" defer></script>
232
232
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
233
233
  <!-- task 1003069 (R08) — the quick-filing form's routed result links a task
@@ -108,7 +108,7 @@
108
108
  BEFORE builders.js so the chrome ids exist when events are wired. -->
109
109
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab" defer></script>
110
110
  <script src="/builders/craft-mode.js?v=2026-10-09-living3" defer></script>
111
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1" defer></script>
111
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1" defer></script>
112
112
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
113
113
  <script src="/builders/palette.js" defer></script>
114
114
  <!-- task 2166: the shared component kit (window.OTBKit) — pager/ledger/rail.
@@ -103,7 +103,7 @@
103
103
 
104
104
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
105
105
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
106
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
106
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
107
107
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
108
108
  <script src="/builders/palette.js" defer></script>
109
109
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
@@ -61,7 +61,7 @@
61
61
 
62
62
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
63
63
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
64
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
64
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
65
65
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
66
66
  <script src="/builders/palette.js" defer></script>
67
67
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -117,7 +117,7 @@
117
117
 
118
118
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
119
119
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
120
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
120
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
121
121
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
122
122
  <script src="/builders/palette.js" defer></script>
123
123
  <!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
@@ -209,7 +209,7 @@
209
209
  chrome exists before the page script runs. -->
210
210
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
211
211
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
212
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
212
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
213
213
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
214
214
  <script src="/builders/palette.js" defer></script>
215
215
  <!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
@@ -72,7 +72,7 @@
72
72
 
73
73
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
74
74
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
75
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
75
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
76
76
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
77
77
  <script src="/builders/palette.js" defer></script>
78
78
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -79,7 +79,7 @@
79
79
  chrome exists before the page script runs. -->
80
80
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
81
81
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
82
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
82
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
83
83
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
84
84
  <script src="/builders/palette.js" defer></script>
85
85
  <!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
@@ -43,7 +43,7 @@
43
43
 
44
44
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
45
45
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
46
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
46
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
47
47
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
48
48
  <script src="/builders/palette.js" defer></script>
49
49
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -55,7 +55,7 @@
55
55
  chrome exists before the page script runs. -->
56
56
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
57
57
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
58
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
58
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
59
59
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
60
60
  <script src="/builders/palette.js" defer></script>
61
61
  <!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
@@ -113,7 +113,7 @@
113
113
  chrome exists before the page script runs. -->
114
114
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
115
115
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
116
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
116
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
117
117
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
118
118
  <script src="/builders/palette.js" defer></script>
119
119
  <!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
@@ -166,6 +166,14 @@
166
166
  return `${head}${warn}<ol class="su-versions" aria-labelledby="su-new-h">${items.join('')}</ol>${more ? `<div class="row-end">${more}</div>` : ''}${beyond}`;
167
167
  }
168
168
 
169
+ // A move this project's own ledger says was rolled back (task 1004730): the server's plain
170
+ // sentence, said as it is. It names the version tried, that it was rolled back, and that
171
+ // the project is still on its old version and working; nothing here re-derives it.
172
+ function heldHtml(held) {
173
+ if (!held || !held.message) return '';
174
+ return `<p class="panel-status" role="status">${escapeHtml(held.message)}</p>`;
175
+ }
176
+
169
177
  function render(data) {
170
178
  const body = byId('su-body');
171
179
  const note = byId('su-note');
@@ -177,19 +185,22 @@
177
185
 
178
186
  if (u.reading !== 'ok') {
179
187
  body.innerHTML = row('This project runs', u.running ? mono(u.running) : 'a version it could not name')
188
+ + heldHtml(data.held)
180
189
  + `<p class="panel-status panel-status--danger" role="status">Could not check for a newer version: ${escapeHtml(u.error || 'no answer')}.</p>`;
181
190
  if (note) note.textContent = notes.join(' ');
182
191
  return;
183
192
  }
184
193
 
185
- let html = row('This project runs', mono(u.running));
194
+ let html = row('This project runs', mono(u.running)) + heldHtml(data.held);
195
+ const onHold = !!(data.held && u.offered && data.held.version === u.offered);
186
196
  if (!u.offered) {
187
197
  html += row('Newest for this project', `${mono(u.running)} — this project is up to date.`, '<span class="su-pill su-pill--ok">Up to date</span>');
188
198
  } else {
189
199
  const when = ago(u.offered_published_at);
190
200
  const pending = data.can_update && data.ask && data.ask.available && askPending(data.ask, u.offered);
191
- html += row('Newest for this project', `${mono(u.offered)}${when ? ` — published ${escapeHtml(when)}` : ''}`, `<span class="su-pill">${pending ? 'Requested' : 'Update ready'}</span>`);
192
- html += doorHtml(data, u.offered);
201
+ html += row('Newest for this project', `${mono(u.offered)}${when ? ` — published ${escapeHtml(when)}` : ''}`, `<span class="su-pill">${onHold ? 'On hold' : pending ? 'Requested' : 'Update ready'}</span>`);
202
+ // No button to take again the very version that was just rolled back here (task 1004730).
203
+ if (!onHold) html += doorHtml(data, u.offered);
193
204
  html += whatsNewHtml(u.whats_new, (data.door || {}).kind === 'local');
194
205
  }
195
206
  // A newer line this project's channel does not take is a fact worth one sentence — it
@@ -472,7 +472,7 @@
472
472
  chrome exists before the page scripts run. -->
473
473
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
474
474
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
475
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
475
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
476
476
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
477
477
  <script src="/builders/palette.js" defer></script>
478
478
  <!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
@@ -498,7 +498,7 @@
498
498
  settings.js is against the 1500-line ratchet. -->
499
499
  <script src="/builders/settings-render.js?v=2026-09-16-render-levels"></script>
500
500
  <!-- task 1004296: Settings → Software update. Own file on the same precedent. -->
501
- <script src="/builders/settings-software-update.js?v=2026-10-06-ask"></script>
501
+ <script src="/builders/settings-software-update.js?v=2026-10-17-hold"></script>
502
502
  <!-- task 1004501: Settings → Your Autobongos runner. Own file on the same precedent. -->
503
503
  <script src="/builders/settings-autobongos.js?v=2026-10-01-autobongos"></script>
504
504
  <!-- task 1003793: Settings → Module install reports. Own file on the same precedent. -->
@@ -774,7 +774,7 @@
774
774
  coreUpdateAsked = true;
775
775
  api.request('GET', '/api/bongos/core-update').then(function (res) {
776
776
  if (!res || res.status !== 200 || !res.data) return;
777
- if (res.data.update) renderCoreUpdateBanner(res.data.update);
777
+ if (res.data.update) renderCoreUpdateBanner(res.data.update, res.data.held);
778
778
  }, function () { /* fail-soft: no banner is the correct answer to no answer */ });
779
779
  }
780
780
 
@@ -789,7 +789,7 @@
789
789
  // is current AND when the registry could not be read; `reading` separates them,
790
790
  // and neither renders. A banner is a claim about being out of date, and a wrong
791
791
  // one on a project that is actually current is worse than silence.
792
- function renderCoreUpdateBanner(update) {
792
+ function renderCoreUpdateBanner(update, held) {
793
793
  if (!update || update.reading !== 'ok' || !update.behind || !update.latest) return;
794
794
  // A dismissal is remembered PER VERSION, not forever: the next release is new
795
795
  // news and must re-announce itself, or the surface is dead after one click.
@@ -826,10 +826,14 @@
826
826
  : (onUpdatePanel
827
827
  ? '<span class="core-update-notice__hint">Its details are below.</span>'
828
828
  : '<a class="core-update-notice__action" href="' + SOFTWARE_UPDATE_HREF + '">Upgrade</a>');
829
- el.innerHTML =
830
- '<span>Core <strong>' + esc(update.latest) + '</strong> is available — this project runs ' +
831
- esc(update.running || 'an unknown version') + '.</span>' +
832
- action +
829
+ // task 1004730: the newest version already failed here and was rolled back. Say so, never
830
+ // "available" with a button to take it again; Software update carries the full sentence.
831
+ var hold = held && held.version === update.latest ? held : null;
832
+ el.innerHTML = (hold
833
+ ? '<span>Core <strong>' + esc(hold.version) + '</strong> was tried on this project and rolled back. It is still on ' +
834
+ esc(hold.still_on) + ' and working.</span><a class="core-update-notice__action" href="' + SOFTWARE_UPDATE_HREF + '">Details</a>'
835
+ : '<span>Core <strong>' + esc(update.latest) + '</strong> is available — this project runs ' +
836
+ esc(update.running || 'an unknown version') + '.</span>' + action) +
833
837
  '<button type="button" class="core-update-notice__close" aria-label="Dismiss">×</button>';
834
838
  el.querySelector('.core-update-notice__close').addEventListener('click', function () {
835
839
  try {
@@ -230,7 +230,7 @@
230
230
 
231
231
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
232
232
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
233
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
233
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
234
234
  <script src="/builders/palette.js" defer></script>
235
235
  <script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
236
236
  <script src="/builders/gov-feeds.js?v=2026-10-09-living3"></script>
@@ -190,7 +190,7 @@
190
190
 
191
191
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
192
192
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
193
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
193
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
194
194
  <script src="/builders/palette.js" defer></script>
195
195
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
196
196
  <!-- The kit, for its ONE renderer: the full-size ship-time visual figure
@@ -56,7 +56,7 @@
56
56
  time so the chrome exists before the deferred page scripts execute. -->
57
57
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
58
58
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
59
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
59
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
60
60
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
61
61
  <script src="/builders/palette.js" defer></script>
62
62
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so task.js can pull from it. -->
@@ -140,7 +140,7 @@
140
140
 
141
141
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
142
142
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
143
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
143
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
144
144
  <script src="/builders/palette.js" defer></script>
145
145
 
146
146
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
@@ -144,7 +144,7 @@
144
144
 
145
145
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
146
146
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
147
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
147
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
148
148
  <script src="/builders/palette.js" defer></script>
149
149
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
150
150
  <script src="/builders/brand-holes.js?v=2026-09-29-aqfix"></script>
@@ -167,7 +167,7 @@
167
167
  chrome exists before the page script runs. -->
168
168
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
169
169
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
170
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
170
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
171
171
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
172
172
  <script src="/builders/palette.js" defer></script>
173
173
  <!-- shared frontend toolkit (window.OTB) — loaded before watch.js, which pulls from it. -->
@@ -173,7 +173,7 @@
173
173
  time so the chrome exists before the deferred page scripts execute. -->
174
174
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
175
175
  <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
176
- <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
176
+ <script src="/builders/shell.js?v=2026-10-17-upgrade-hold1"></script>
177
177
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
178
178
  <script src="/builders/palette.js" defer></script>
179
179
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so work.js can pull from it. -->
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.145",
3
+ "version": "1.21.146",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.21.145",
9
+ "version": "1.21.146",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.145",
3
+ "version": "1.21.146",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -9884,5 +9884,11 @@
9884
9884
  "id": "1004348",
9885
9885
  "text": "The Blockers page now uses the owner's own words, written on a Chromebook and brought back from Google Docs. The line under the page title is shorter and plainer, and the button reads \"+ File blocker\". Both rewritten lines wen"
9886
9886
  }
9887
+ ],
9888
+ "1.21.146": [
9889
+ {
9890
+ "id": "1004730",
9891
+ "text": "When an automatic core update fails on a hosted project and is rolled back, that version is not retried over and over, and the project's owner now sees in their own Settings and update banner which version was tried, that it w"
9892
+ }
9887
9893
  ]
9888
9894
  }
@@ -23,8 +23,16 @@
23
23
  // re-queue a target that already failed, every tick, forever. A target is held for an
24
24
  // instance when it already has, FOR THAT TARGET: a core-upgrade that ended (error, or
25
25
  // done but the box is still behind), a preflight intent that errored, or a stored
26
- // preflight verdict that refused. A newer release is a new target and is not held. The
27
- // richer hold — telling the project owner, releasing it — is task 1004730.
26
+ // preflight verdict that refused. A newer release is a new target and is not held.
27
+ //
28
+ // BY FAILURE CLASS (task 1004730). A failed intent records WHAT KIND of failure it was
29
+ // (upgrade-outcome.js classifyFailure, stored by the drain loop). A `transient` one (a
30
+ // registry blip, an install that could not download) already waited out its own
31
+ // 15m/1h/6h backoff inside the intent (intent-retry.js) before it was retired, so this
32
+ // path may try that same target once more after TRANSIENT_HOLD_MS. Every other class (a
33
+ // known wedge whose one fix did not hold, a rule refusing it, an unknown, a failed
34
+ // rollback, which move-escalation.js already took to a person) stays held until a newer
35
+ // release. The project's own hall tells its owner: src/bongos/upgrade-hold.js.
28
36
  //
29
37
  // Carved into its own file because provision.js and provision-core-upgrade.js sit at
30
38
  // the size ratchet. Best-effort: nothing here may fail the tick.
@@ -35,6 +43,11 @@ const { resolveEnv } = require('../../src/instance-config');
35
43
  // restarts every hosted project at once. The tick runs every few minutes; one is plenty.
36
44
  const AUTO_MOVES_PER_TICK = 1;
37
45
 
46
+ // How long a target whose failure was classed transient waits before this path tries it
47
+ // again (task 1004730): a day, the hold the self-host sweep gives a failed version
48
+ // (update-sweep.js REFUSAL_HOLD_MS).
49
+ const TRANSIENT_HOLD_MS = 24 * 60 * 60 * 1000;
50
+
38
51
  const REQUESTED_BY = 'runner:auto-upgrade';
39
52
  const OPEN_STATES = new Set(['pending', 'running']);
40
53
  const OFF_VALUES = new Set(['off', '0', 'false', 'no', 'disabled']);
@@ -57,6 +70,15 @@ function parseVerdict(p) {
57
70
  return p;
58
71
  }
59
72
 
73
+ // Does this failed intent still hold its target at `now`? A transient error holds for
74
+ // TRANSIENT_HOLD_MS from when it was retired; anything else holds until a newer release
75
+ // (task 1004730). An unreadable time reads as "just now", the safe direction. PURE.
76
+ function stillHolds(i, now) {
77
+ if (i.failure_class !== 'transient' || i.state !== 'error') return true;
78
+ const at = Date.parse(i.updated_at);
79
+ return !Number.isFinite(at) || now - at < TRANSIENT_HOLD_MS;
80
+ }
81
+
60
82
  /**
61
83
  * What, if anything, to queue for one project. PURE.
62
84
  * @param {object} inst provisioning_instances row joined with its core-version snapshot
@@ -64,7 +86,7 @@ function parseVerdict(p) {
64
86
  * @param {object} channelMod update-channel.js
65
87
  * @returns {{ action: string, to: string } | { skip: string }}
66
88
  */
67
- function decideAutoMove(inst, intents, channelMod) {
89
+ function decideAutoMove(inst, intents, channelMod, now = Date.now()) {
68
90
  if (inst.hosting_shape !== 'cloud-host') return { skip: 'not a hosted project' }; // never the control-plane row
69
91
  if (inst.status !== 'active') return { skip: 'not active' };
70
92
  if (channelMod.normalizeChannel(inst.update_channel) === 'pinned') return { skip: 'pinned' };
@@ -75,7 +97,7 @@ function decideAutoMove(inst, intents, channelMod) {
75
97
  const same = (i) => String(i.target_version || '') === String(to);
76
98
  const held = intents.some((i) => same(i) && (
77
99
  (i.action === 'core-upgrade' && (i.state === 'error' || i.state === 'done'))
78
- || (i.action === 'core-upgrade-preflight' && i.state === 'error')));
100
+ || (i.action === 'core-upgrade-preflight' && i.state === 'error')) && stillHolds(i, now));
79
101
  const verdict = parseVerdict(inst.preflight);
80
102
  const verdictForTarget = verdict && String(verdict.target || '') === String(to) ? verdict : null;
81
103
  if (held || (verdictForTarget && verdictForTarget.ok !== true)) return { skip: `held: ${to} already failed here` };
@@ -95,6 +117,7 @@ async function autoUpgradeTick(deps) {
95
117
  }
96
118
  const channelMod = deps.updateChannel || require('./update-channel.js');
97
119
  let queued = 0;
120
+ const now = (deps.now || Date.now)();
98
121
  try {
99
122
  const { rows } = await db.query(
100
123
  `SELECT i.id, i.slug, i.owner_builder_id, i.hosting_shape, i.status, i.update_channel,
@@ -105,7 +128,7 @@ async function autoUpgradeTick(deps) {
105
128
  ORDER BY i.id`);
106
129
  if (!rows.length) return { queued };
107
130
  const { rows: intents } = await db.query(
108
- `SELECT instance_id, action, state, target_version FROM provisioning_intents
131
+ `SELECT instance_id, action, state, target_version, failure_class, updated_at FROM provisioning_intents
109
132
  WHERE instance_id = ANY($1)
110
133
  AND (state IN ('pending', 'running')
111
134
  OR (action IN ('core-upgrade', 'core-upgrade-preflight') AND target_version IS NOT NULL))`,
@@ -113,7 +136,7 @@ async function autoUpgradeTick(deps) {
113
136
  for (const inst of rows) {
114
137
  if (queued >= AUTO_MOVES_PER_TICK) break;
115
138
  const mine = intents.filter((i) => String(i.instance_id) === String(inst.id));
116
- const d = decideAutoMove(inst, mine, channelMod);
139
+ const d = decideAutoMove(inst, mine, channelMod, now);
117
140
  if (d.skip) { if (d.skip.startsWith('held')) log(` auto core-upgrade: ${inst.slug} ${d.skip}`); continue; }
118
141
  try {
119
142
  const r = await provisioning.enqueueIntent(db, inst.id, d.action, REQUESTED_BY, d.to);
@@ -136,4 +159,4 @@ async function autoUpgradeTick(deps) {
136
159
  return { queued };
137
160
  }
138
161
 
139
- module.exports = { AUTO_MOVES_PER_TICK, autoUpgradeEnabled, autoUpgradeTick };
162
+ module.exports = { AUTO_MOVES_PER_TICK, TRANSIENT_HOLD_MS, autoUpgradeEnabled, autoUpgradeTick };