@bongos/core 1.19.922 → 1.19.924
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 +48 -28
- package/docs/adr/0322-a-remnant-needs-evidence-and-merged-wins.md +110 -0
- package/docs/adr/README.md +1 -0
- package/docs/copy-inventory.md +22 -15
- package/docs/copy-registry.json +81 -18
- package/docs/module-api-changelog.md +4 -0
- package/modules/economy/reward.js +11 -0
- package/modules/hall-ui/public/deploy.html +1 -1
- package/modules/hall-ui/public/deploy.js +103 -3
- package/modules/hall-ui/public/project-settings.css +39 -0
- package/modules/ideas/idea-state.js +254 -0
- package/modules/ideas/routes/inbox.js +8 -0
- package/modules/ideas/trail.js +13 -1
- package/modules/provisioning/core-upgrade.js +24 -5
- package/modules/provisioning/migrations/provisioning_020_core_upgrade_preflight.sql +53 -0
- package/modules/provisioning/provisioning.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/provision-core-upgrade.js +123 -66
- package/scripts/gds/provision.js +2 -1
- package/src/module-api.js +1 -1
- package/tests/core_upgrade_door.mjs +56 -4
- package/tests/core_upgrade_runner.mjs +82 -0
- package/tests/deploy_page_projects.mjs +104 -5
- package/tests/idea_state.mjs +399 -0
package/docs/copy-registry.json
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"generator": "scripts/gds/copy-inventory.js",
|
|
4
4
|
"goal": 1000074,
|
|
5
5
|
"counts": {
|
|
6
|
-
"strings":
|
|
7
|
-
"unique_ids":
|
|
8
|
-
"certain":
|
|
6
|
+
"strings": 1839,
|
|
7
|
+
"unique_ids": 1596,
|
|
8
|
+
"certain": 1839,
|
|
9
9
|
"heuristic": 0,
|
|
10
10
|
"duplicate_ids": 166
|
|
11
11
|
},
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"builders-hall": {
|
|
14
14
|
"at": "modules/hall-ui/public",
|
|
15
15
|
"files": 84,
|
|
16
|
-
"strings":
|
|
16
|
+
"strings": 1349
|
|
17
17
|
},
|
|
18
18
|
"status-dashboard": {
|
|
19
19
|
"at": "modules/status-ui/public",
|
|
@@ -1011,8 +1011,8 @@
|
|
|
1011
1011
|
"text": "Move to {…}",
|
|
1012
1012
|
"occurrences": 2,
|
|
1013
1013
|
"at": [
|
|
1014
|
-
"modules/hall-ui/public/deploy.js:
|
|
1015
|
-
"modules/hall-ui/public/deploy.js:
|
|
1014
|
+
"modules/hall-ui/public/deploy.js:218",
|
|
1015
|
+
"modules/hall-ui/public/deploy.js:314"
|
|
1016
1016
|
]
|
|
1017
1017
|
},
|
|
1018
1018
|
{
|
|
@@ -1840,6 +1840,15 @@
|
|
|
1840
1840
|
"origin": "js-markup",
|
|
1841
1841
|
"confidence": "certain"
|
|
1842
1842
|
},
|
|
1843
|
+
{
|
|
1844
|
+
"id": "af615fa9f404",
|
|
1845
|
+
"surface": "builders-hall",
|
|
1846
|
+
"text": "(checked {…})",
|
|
1847
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
1848
|
+
"line": 152,
|
|
1849
|
+
"origin": "js-markup",
|
|
1850
|
+
"confidence": "certain"
|
|
1851
|
+
},
|
|
1843
1852
|
{
|
|
1844
1853
|
"id": "544794f1ec8f",
|
|
1845
1854
|
"surface": "builders-hall",
|
|
@@ -3154,6 +3163,15 @@
|
|
|
3154
3163
|
"origin": "js-markup",
|
|
3155
3164
|
"confidence": "certain"
|
|
3156
3165
|
},
|
|
3166
|
+
{
|
|
3167
|
+
"id": "f66f5cdaa732",
|
|
3168
|
+
"surface": "builders-hall",
|
|
3169
|
+
"text": "Checked against {…} — nothing blocks this move.{…}",
|
|
3170
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
3171
|
+
"line": 155,
|
|
3172
|
+
"origin": "js-markup",
|
|
3173
|
+
"confidence": "certain"
|
|
3174
|
+
},
|
|
3157
3175
|
{
|
|
3158
3176
|
"id": "f8725cf3ba62",
|
|
3159
3177
|
"surface": "builders-hall",
|
|
@@ -3172,6 +3190,15 @@
|
|
|
3172
3190
|
"origin": "js-text-assign",
|
|
3173
3191
|
"confidence": "certain"
|
|
3174
3192
|
},
|
|
3193
|
+
{
|
|
3194
|
+
"id": "69da40d030b0",
|
|
3195
|
+
"surface": "builders-hall",
|
|
3196
|
+
"text": "Checking what this would do…",
|
|
3197
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
3198
|
+
"line": 145,
|
|
3199
|
+
"origin": "js-markup",
|
|
3200
|
+
"confidence": "certain"
|
|
3201
|
+
},
|
|
3175
3202
|
{
|
|
3176
3203
|
"id": "aa3ba7d28a76",
|
|
3177
3204
|
"surface": "builders-hall",
|
|
@@ -3942,7 +3969,7 @@
|
|
|
3942
3969
|
"surface": "builders-hall",
|
|
3943
3970
|
"text": "Could not read this project's deploy state: {…}",
|
|
3944
3971
|
"file": "modules/hall-ui/public/deploy.js",
|
|
3945
|
-
"line":
|
|
3972
|
+
"line": 254,
|
|
3946
3973
|
"origin": "js-markup",
|
|
3947
3974
|
"confidence": "certain"
|
|
3948
3975
|
},
|
|
@@ -6588,7 +6615,7 @@
|
|
|
6588
6615
|
"surface": "builders-hall",
|
|
6589
6616
|
"text": "Move to {…}",
|
|
6590
6617
|
"file": "modules/hall-ui/public/deploy.js",
|
|
6591
|
-
"line":
|
|
6618
|
+
"line": 218,
|
|
6592
6619
|
"origin": "js-markup",
|
|
6593
6620
|
"confidence": "certain"
|
|
6594
6621
|
},
|
|
@@ -6597,7 +6624,7 @@
|
|
|
6597
6624
|
"surface": "builders-hall",
|
|
6598
6625
|
"text": "Move to {…}",
|
|
6599
6626
|
"file": "modules/hall-ui/public/deploy.js",
|
|
6600
|
-
"line":
|
|
6627
|
+
"line": 314,
|
|
6601
6628
|
"origin": "js-text-assign",
|
|
6602
6629
|
"confidence": "certain"
|
|
6603
6630
|
},
|
|
@@ -6921,7 +6948,7 @@
|
|
|
6921
6948
|
"surface": "builders-hall",
|
|
6922
6949
|
"text": "No running box to deploy.",
|
|
6923
6950
|
"file": "modules/hall-ui/public/deploy.js",
|
|
6924
|
-
"line":
|
|
6951
|
+
"line": 292,
|
|
6925
6952
|
"origin": "js-markup",
|
|
6926
6953
|
"confidence": "certain"
|
|
6927
6954
|
},
|
|
@@ -7033,6 +7060,15 @@
|
|
|
7033
7060
|
"origin": "js-markup",
|
|
7034
7061
|
"confidence": "certain"
|
|
7035
7062
|
},
|
|
7063
|
+
{
|
|
7064
|
+
"id": "428a62539050",
|
|
7065
|
+
"surface": "builders-hall",
|
|
7066
|
+
"text": "Not checked yet — the runner takes this reading on its own tick.",
|
|
7067
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
7068
|
+
"line": 150,
|
|
7069
|
+
"origin": "js-markup",
|
|
7070
|
+
"confidence": "certain"
|
|
7071
|
+
},
|
|
7036
7072
|
{
|
|
7037
7073
|
"id": "c72e0bdb834a",
|
|
7038
7074
|
"surface": "builders-hall",
|
|
@@ -7200,7 +7236,7 @@
|
|
|
7200
7236
|
"surface": "builders-hall",
|
|
7201
7237
|
"text": "Nothing newer is published that this box can take. There is nothing to deploy.",
|
|
7202
7238
|
"file": "modules/hall-ui/public/deploy.js",
|
|
7203
|
-
"line":
|
|
7239
|
+
"line": 237,
|
|
7204
7240
|
"origin": "js-markup",
|
|
7205
7241
|
"confidence": "certain"
|
|
7206
7242
|
},
|
|
@@ -8775,7 +8811,7 @@
|
|
|
8775
8811
|
"surface": "builders-hall",
|
|
8776
8812
|
"text": "See what would change",
|
|
8777
8813
|
"file": "modules/hall-ui/public/deploy.js",
|
|
8778
|
-
"line":
|
|
8814
|
+
"line": 121,
|
|
8779
8815
|
"origin": "js-markup",
|
|
8780
8816
|
"confidence": "certain"
|
|
8781
8817
|
},
|
|
@@ -8847,7 +8883,7 @@
|
|
|
8847
8883
|
"surface": "builders-hall",
|
|
8848
8884
|
"text": "Serving {…} — read from the box itself, {…}.",
|
|
8849
8885
|
"file": "modules/hall-ui/public/deploy.js",
|
|
8850
|
-
"line":
|
|
8886
|
+
"line": 239,
|
|
8851
8887
|
"origin": "js-markup",
|
|
8852
8888
|
"confidence": "certain"
|
|
8853
8889
|
},
|
|
@@ -10120,6 +10156,15 @@
|
|
|
10120
10156
|
"origin": "html-text",
|
|
10121
10157
|
"confidence": "certain"
|
|
10122
10158
|
},
|
|
10159
|
+
{
|
|
10160
|
+
"id": "8c991355687d",
|
|
10161
|
+
"surface": "builders-hall",
|
|
10162
|
+
"text": "The upgrade checked {…} and refused:{…}",
|
|
10163
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
10164
|
+
"line": 160,
|
|
10165
|
+
"origin": "js-markup",
|
|
10166
|
+
"confidence": "certain"
|
|
10167
|
+
},
|
|
10123
10168
|
{
|
|
10124
10169
|
"id": "a42a37c43bfb",
|
|
10125
10170
|
"surface": "builders-hall",
|
|
@@ -10431,7 +10476,7 @@
|
|
|
10431
10476
|
"surface": "builders-hall",
|
|
10432
10477
|
"text": "This platform",
|
|
10433
10478
|
"file": "modules/hall-ui/public/deploy.js",
|
|
10434
|
-
"line":
|
|
10479
|
+
"line": 284,
|
|
10435
10480
|
"origin": "js-markup",
|
|
10436
10481
|
"confidence": "certain"
|
|
10437
10482
|
},
|
|
@@ -10440,7 +10485,7 @@
|
|
|
10440
10485
|
"surface": "builders-hall",
|
|
10441
10486
|
"text": "This restarts {…} onto core",
|
|
10442
10487
|
"file": "modules/hall-ui/public/deploy.js",
|
|
10443
|
-
"line":
|
|
10488
|
+
"line": 218,
|
|
10444
10489
|
"origin": "js-markup",
|
|
10445
10490
|
"confidence": "certain"
|
|
10446
10491
|
},
|
|
@@ -10480,6 +10525,15 @@
|
|
|
10480
10525
|
"origin": "js-markup",
|
|
10481
10526
|
"confidence": "certain"
|
|
10482
10527
|
},
|
|
10528
|
+
{
|
|
10529
|
+
"id": "4301ecd67891",
|
|
10530
|
+
"surface": "builders-hall",
|
|
10531
|
+
"text": "This would fail.",
|
|
10532
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
10533
|
+
"line": 160,
|
|
10534
|
+
"origin": "js-markup",
|
|
10535
|
+
"confidence": "certain"
|
|
10536
|
+
},
|
|
10483
10537
|
{
|
|
10484
10538
|
"id": "2ad5823d2cd7",
|
|
10485
10539
|
"surface": "builders-hall",
|
|
@@ -11173,6 +11227,15 @@
|
|
|
11173
11227
|
"origin": "js-notice",
|
|
11174
11228
|
"confidence": "certain"
|
|
11175
11229
|
},
|
|
11230
|
+
{
|
|
11231
|
+
"id": "921cb15a8188",
|
|
11232
|
+
"surface": "builders-hall",
|
|
11233
|
+
"text": "You can still press Move — the runner will refuse it the same way, and the box is left where it is.",
|
|
11234
|
+
"file": "modules/hall-ui/public/deploy.js",
|
|
11235
|
+
"line": 160,
|
|
11236
|
+
"origin": "js-markup",
|
|
11237
|
+
"confidence": "certain"
|
|
11238
|
+
},
|
|
11176
11239
|
{
|
|
11177
11240
|
"id": "b31fc908c962",
|
|
11178
11241
|
"surface": "builders-hall",
|
|
@@ -12168,7 +12231,7 @@
|
|
|
12168
12231
|
"surface": "builders-hall",
|
|
12169
12232
|
"text": "is published and this box is not on it yet.",
|
|
12170
12233
|
"file": "modules/hall-ui/public/deploy.js",
|
|
12171
|
-
"line":
|
|
12234
|
+
"line": 121,
|
|
12172
12235
|
"origin": "js-markup",
|
|
12173
12236
|
"confidence": "certain"
|
|
12174
12237
|
},
|
|
@@ -12303,7 +12366,7 @@
|
|
|
12303
12366
|
"surface": "builders-hall",
|
|
12304
12367
|
"text": "no reading",
|
|
12305
12368
|
"file": "modules/hall-ui/public/deploy.js",
|
|
12306
|
-
"line":
|
|
12369
|
+
"line": 104,
|
|
12307
12370
|
"origin": "js-markup",
|
|
12308
12371
|
"confidence": "certain"
|
|
12309
12372
|
},
|
|
@@ -12555,7 +12618,7 @@
|
|
|
12555
12618
|
"surface": "builders-hall",
|
|
12556
12619
|
"text": "reads the control plane's own observation · ADR 0293 · every move is recorded with who asked",
|
|
12557
12620
|
"file": "modules/hall-ui/public/deploy.js",
|
|
12558
|
-
"line":
|
|
12621
|
+
"line": 296,
|
|
12559
12622
|
"origin": "js-markup",
|
|
12560
12623
|
"confidence": "certain"
|
|
12561
12624
|
},
|
|
@@ -2318,5 +2318,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2318
2318
|
landed since 1.19.920 with no explicit bump. run 35534076467. (task 1002620)
|
|
2319
2319
|
1.19.922 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2320
2320
|
landed since 1.19.921 with no explicit bump. run 35536293721. (task 1002620)
|
|
2321
|
+
1.19.923 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2322
|
+
landed since 1.19.922 with no explicit bump. run 35541278656. (task 1002620)
|
|
2323
|
+
1.19.924 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2324
|
+
landed since 1.19.923 with no explicit bump. run 35541674047. (task 1002620)
|
|
2321
2325
|
---------------------------------------------------------------------------
|
|
2322
2326
|
```
|
|
@@ -21,6 +21,7 @@ const cost = require('./cost');
|
|
|
21
21
|
const streak = require('./streak');
|
|
22
22
|
const ideaSizeLib = require('./idea-size');
|
|
23
23
|
const ideaSizeHistorical = require('./idea-size-historical');
|
|
24
|
+
const ideaBrightnessLib = require('./idea-brightness');
|
|
24
25
|
|
|
25
26
|
module.exports = {
|
|
26
27
|
// credit allocation — transaction-participant: caller passes its tx `client`
|
|
@@ -110,6 +111,16 @@ module.exports = {
|
|
|
110
111
|
// projection and quietly drops a field the pricing needs.
|
|
111
112
|
descentRowsFromTrail: (...a) => ideaSizeHistorical.descentRowsFromTrail(...a),
|
|
112
113
|
get IDEA_SIZE_SCALE_REF() { return ideaSizeLib.IDEA_SIZE_SCALE_REF; },
|
|
114
|
+
// BRIGHTNESS — the live share of that descent (task 1004099 / BV2.R16), on the
|
|
115
|
+
// port for the same reason size is. It is the SECOND of the two channels, and
|
|
116
|
+
// the pair is what BV2.R17 resolves the five states from: a thought that
|
|
117
|
+
// earned nothing (`hasWork: false`) and one whose work was all torn out
|
|
118
|
+
// (`share: 0`) are different objects in the sky, and only a caller holding
|
|
119
|
+
// BOTH fields can tell them apart. Shipping size without this left the ideas
|
|
120
|
+
// module able to draw how big a thought was and unable to say whether it was
|
|
121
|
+
// still alive.
|
|
122
|
+
ideaBrightness: (...a) => ideaBrightnessLib.ideaBrightness(...a),
|
|
123
|
+
ideaBrightnesses: (...a) => ideaBrightnessLib.ideaBrightnesses(...a),
|
|
113
124
|
computeStreak: (...a) => streak.computeStreak(...a),
|
|
114
125
|
wouldExtendStreak: (...a) => streak.wouldExtendStreak(...a),
|
|
115
126
|
};
|
|
@@ -59,6 +59,6 @@
|
|
|
59
59
|
<script src="/builders/palette.js" defer></script>
|
|
60
60
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
61
61
|
<script src="/builders/hall-kit.js"></script>
|
|
62
|
-
<script src="/builders/deploy.js?v=2026-09-
|
|
62
|
+
<script src="/builders/deploy.js?v=2026-09-20-preflight2"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -50,6 +50,19 @@
|
|
|
50
50
|
// instance_id -> 'preview' | 'confirm'. Held per box so opening the confirm on one does
|
|
51
51
|
// not arm it on another.
|
|
52
52
|
const steps = new Map();
|
|
53
|
+
// Rows whose dry run is in flight — per box, like `steps`, because a page-wide flag
|
|
54
|
+
// would spin every other project's row on one project's check.
|
|
55
|
+
const checking = new Set();
|
|
56
|
+
// How long the page waits for the runner to answer. Read off `window` when present so
|
|
57
|
+
// a harness can drive the loop without sleeping through it — a test that injects the
|
|
58
|
+
// real timer spends 30s of wall-clock per non-converging case and keeps repainting a
|
|
59
|
+
// sandbox that has already been torn down.
|
|
60
|
+
// `|| 2000` would be a bug here: an override of 0 — the one a harness wants — is
|
|
61
|
+
// falsy, so the fallback would swallow it and the test would sleep the full interval
|
|
62
|
+
// anyway while appearing to be driven.
|
|
63
|
+
const num = (v, dflt) => (Number.isFinite(v) ? v : dflt);
|
|
64
|
+
const POLL_MS = typeof window !== 'undefined' ? num(window.__deployPollMs, 2000) : 2000;
|
|
65
|
+
const POLL_TRIES = typeof window !== 'undefined' ? num(window.__deployPollTries, 15) : 15;
|
|
53
66
|
|
|
54
67
|
async function fetchJson(path) {
|
|
55
68
|
const res = await api.request('GET', `${API}${path}`);
|
|
@@ -117,10 +130,94 @@
|
|
|
117
130
|
// to that button closes over this same preview object — so the owner confirms the thing
|
|
118
131
|
// they were shown rather than "the newest", which is a different act by the time it is
|
|
119
132
|
// resolved.
|
|
133
|
+
// What the dry run said, from the runner's own tick (task 1004121). Before this, step
|
|
134
|
+
// one made NO network call — it redrew a fixed sentence and called that a preview. The
|
|
135
|
+
// owner pressed it four times on 2026-09-20, restarted four live boxes, and learned
|
|
136
|
+
// three different pre-flight refusals one production restart at a time. Every one of
|
|
137
|
+
// them was in this verdict already.
|
|
138
|
+
//
|
|
139
|
+
// A REFUSAL DOES NOT DISABLE THE BUTTON. The runner refuses on its own, and this
|
|
140
|
+
// reading can be minutes old; a control that blocked on a stale ✖ would be lying in
|
|
141
|
+
// the other direction. Say what will happen and let the owner decide.
|
|
142
|
+
function preflightHtml(p) {
|
|
143
|
+
const pf = p.preflight;
|
|
144
|
+
if (checking.has(String(p.instance_id)) && !(pf && pf.target === p.recommended_version)) {
|
|
145
|
+
return `<p class="ov-row__sub dp-preflight dp-preflight--checking">Checking what this would do…</p>`;
|
|
146
|
+
}
|
|
147
|
+
// No verdict is its own state, and it is NOT "fine". A silent gap here is how the
|
|
148
|
+
// page used to promise a preview it never performed.
|
|
149
|
+
if (!pf) {
|
|
150
|
+
return `<p class="ov-row__sub dp-preflight dp-preflight--none">Not checked yet — the runner takes this reading on its own tick.</p>`;
|
|
151
|
+
}
|
|
152
|
+
const when = pf && p.preflight_at ? ` <span class="dp-preflight__age">(checked ${escapeHtml(ago(p.preflight_at))})</span>` : '';
|
|
153
|
+
if (pf.ok) {
|
|
154
|
+
const lines = (pf.lines || []).map((l) => `<li>${escapeHtml(String(l))}</li>`).join('');
|
|
155
|
+
return `<div class="dp-preflight dp-preflight--ok">
|
|
156
|
+
<p class="ov-row__sub">Checked against ${escapeHtml(String(pf.target))} — nothing blocks this move.${when}</p>
|
|
157
|
+
${lines ? `<ul class="dp-preflight__list">${lines}</ul>` : ''}
|
|
158
|
+
</div>`;
|
|
159
|
+
}
|
|
160
|
+
return `<div class="dp-preflight dp-preflight--blocked">
|
|
161
|
+
<p class="ov-row__sub"><strong>This would fail.</strong> The upgrade checked ${escapeHtml(String(pf.target))} and refused:${when}</p>
|
|
162
|
+
<pre class="dp-preflight__error">${escapeHtml(String(pf.error || 'no reason given'))}</pre>
|
|
163
|
+
<p class="ov-row__sub">You can still press Move — the runner will refuse it the same way, and the box is left where it is.</p>
|
|
164
|
+
</div>`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Arming ASKS for the check (task 1004121). The web tier has no shell — it queues the
|
|
168
|
+
// dry run as an intent and the runner answers, which is the same division of labour as
|
|
169
|
+
// every other fact on this page. Then it re-reads the preview until the verdict lands.
|
|
170
|
+
//
|
|
171
|
+
// Only when there isn't already a fresh one: a verdict for THIS target is the answer,
|
|
172
|
+
// and re-asking would spend a subprocess to reprint it.
|
|
173
|
+
const asked = new Set();
|
|
174
|
+
async function askPreflight(p) {
|
|
175
|
+
const id = String(p.instance_id);
|
|
176
|
+
if (p.preflight && p.preflight.target === p.recommended_version) return;
|
|
177
|
+
if (asked.has(id)) return;
|
|
178
|
+
asked.add(id);
|
|
179
|
+
checking.add(id);
|
|
180
|
+
repaint();
|
|
181
|
+
try {
|
|
182
|
+
await sendJson('POST', `/provisioning/instances/${id}/core-upgrade`, {
|
|
183
|
+
to: p.recommended_version, dry_run: true,
|
|
184
|
+
});
|
|
185
|
+
} catch (e) {
|
|
186
|
+
if (e && e.kind === '401') return;
|
|
187
|
+
// A refused REQUEST is not a refused upgrade, and must not be painted as one:
|
|
188
|
+
// fall back to "not checked", which is honest about what is known.
|
|
189
|
+
checking.delete(id); asked.delete(id); repaint();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// The runner drains on its own tick, so this waits rather than assuming. Bounded:
|
|
193
|
+
// a check that never lands leaves the row saying it was never checked, which is
|
|
194
|
+
// true, instead of spinning for ever.
|
|
195
|
+
//
|
|
196
|
+
// AND IT STOPS WHEN NOBODY IS LOOKING. The loop is started from a click and not
|
|
197
|
+
// awaited by it, so without this it outlives whatever closed the row — cancelling,
|
|
198
|
+
// confirming, or a reload — and goes on repainting a step the owner has left. It
|
|
199
|
+
// also made every test that never converges sit through the full ~30s in real time.
|
|
200
|
+
for (let i = 0; i < POLL_TRIES; i++) {
|
|
201
|
+
await new Promise((r) => setTimeout(r, POLL_MS));
|
|
202
|
+
if (steps.get(p.instance_id) !== 'confirm') break; // the row was closed; stop.
|
|
203
|
+
try {
|
|
204
|
+
await refreshOne(p, { keepStep: true });
|
|
205
|
+
const now = (view.self && String(view.self.instance_id) === id)
|
|
206
|
+
? view.self
|
|
207
|
+
: view.boxes.find((b) => String(b.instance_id) === id);
|
|
208
|
+
if (now && now.preflight && now.preflight.target === now.recommended_version) break;
|
|
209
|
+
} catch (e) { break; }
|
|
210
|
+
}
|
|
211
|
+
checking.delete(id);
|
|
212
|
+
asked.delete(id);
|
|
213
|
+
repaint();
|
|
214
|
+
}
|
|
215
|
+
|
|
120
216
|
function stepTwoHtml(p, isSelf) {
|
|
121
217
|
const id = escapeHtml(String(p.instance_id));
|
|
122
218
|
return `
|
|
123
219
|
<div class="ps-controls">
|
|
220
|
+
${preflightHtml(p)}
|
|
124
221
|
<p class="ov-row__sub">This restarts ${isSelf ? 'the platform' : escapeHtml(String(p.slug))} onto core
|
|
125
222
|
<strong>${escapeHtml(String(p.recommended_version))}</strong>. It waits for the box to answer and
|
|
126
223
|
puts itself back on ${escapeHtml(String(p.served_version))} if it does not.</p>
|
|
@@ -166,7 +263,7 @@
|
|
|
166
263
|
function wire(p) {
|
|
167
264
|
const id = String(p.instance_id);
|
|
168
265
|
const preview = $(`dp-preview-${id}`);
|
|
169
|
-
if (preview) preview.addEventListener('click', () => { steps.set(p.instance_id, 'confirm'); repaint(); });
|
|
266
|
+
if (preview) preview.addEventListener('click', () => { steps.set(p.instance_id, 'confirm'); repaint(); askPreflight(p); });
|
|
170
267
|
const cancel = $(`dp-cancel-${id}`);
|
|
171
268
|
if (cancel) cancel.addEventListener('click', () => { steps.set(p.instance_id, 'preview'); repaint(); });
|
|
172
269
|
const confirm = $(`dp-confirm-${id}`);
|
|
@@ -223,14 +320,17 @@
|
|
|
223
320
|
// far wider than the change — it also re-probes boxes the owner never touched. A
|
|
224
321
|
// failure here falls back to the full read, because a stale row on a deploy page is
|
|
225
322
|
// the one thing worse than an extra request.
|
|
226
|
-
|
|
323
|
+
// `keepStep` is for the pre-flight poll (task 1004121): a refresh AFTER a move should
|
|
324
|
+
// return the row to step one, but a refresh DURING the wait must not — it would close
|
|
325
|
+
// the panel the owner is reading, under them, every two seconds.
|
|
326
|
+
async function refreshOne(p, { keepStep = false } = {}) {
|
|
227
327
|
const id = String(p.instance_id);
|
|
228
328
|
const isSelf = view.self && String(view.self.instance_id) === id;
|
|
229
329
|
try {
|
|
230
330
|
const d = await fetchJson(isSelf ? '/provisioning/control-plane' : `/provisioning/instances/${id}/core-upgrade`);
|
|
231
331
|
if (isSelf) view.self = d.preview;
|
|
232
332
|
else view.boxes = view.boxes.map((b) => (String(b.instance_id) === id ? d.preview : b));
|
|
233
|
-
steps.set(p.instance_id, 'preview');
|
|
333
|
+
if (!keepStep) steps.set(p.instance_id, 'preview');
|
|
234
334
|
repaint();
|
|
235
335
|
} catch (e) {
|
|
236
336
|
if (e && e.kind === '401') return;
|
|
@@ -88,3 +88,42 @@
|
|
|
88
88
|
color: var(--ink-soft);
|
|
89
89
|
}
|
|
90
90
|
.ps-sibling strong { color: inherit; font-weight: 600; }
|
|
91
|
+
|
|
92
|
+
/* The deploy control's pre-flight verdict (task 1004121) — what the upgrade says it
|
|
93
|
+
would do, taken by the runner's dry run. Three states, and "not checked" is one of
|
|
94
|
+
them: the page used to show a confident sentence where it had performed no check at
|
|
95
|
+
all, so silence here must look like silence, not like a pass. */
|
|
96
|
+
.dp-preflight { margin: 0 0 0.6rem; }
|
|
97
|
+
.dp-preflight--none,
|
|
98
|
+
.dp-preflight--checking { color: var(--ink-soft); font-style: italic; }
|
|
99
|
+
/* The pass state earns a mark of its own. Without one, "nothing blocks this" and "not
|
|
100
|
+
checked" differ only in wording, and the three-state legibility this file claims is
|
|
101
|
+
two states and a sentence. */
|
|
102
|
+
.dp-preflight--ok {
|
|
103
|
+
border-left: 3px solid var(--ok);
|
|
104
|
+
padding-left: 0.7rem;
|
|
105
|
+
}
|
|
106
|
+
.dp-preflight__age { color: var(--ink-soft); font-weight: normal; }
|
|
107
|
+
.dp-preflight__list {
|
|
108
|
+
margin: 0.25rem 0 0;
|
|
109
|
+
padding-left: 1.1rem;
|
|
110
|
+
color: var(--ink-soft);
|
|
111
|
+
font-size: 0.86rem;
|
|
112
|
+
line-height: 1.5;
|
|
113
|
+
}
|
|
114
|
+
.dp-preflight--blocked {
|
|
115
|
+
border-left: 3px solid var(--danger);
|
|
116
|
+
padding-left: 0.7rem;
|
|
117
|
+
}
|
|
118
|
+
/* The refusal is upgrade.js's own words, multi-line and already indented to name the
|
|
119
|
+
fix — preserved rather than reflowed, because the wording IS the instruction. */
|
|
120
|
+
.dp-preflight__error {
|
|
121
|
+
margin: 0.35rem 0;
|
|
122
|
+
padding: 0.5rem 0.6rem;
|
|
123
|
+
background: var(--surface-2);
|
|
124
|
+
border-radius: 6px;
|
|
125
|
+
font-size: 0.82rem;
|
|
126
|
+
line-height: 1.45;
|
|
127
|
+
white-space: pre-wrap;
|
|
128
|
+
overflow-x: auto;
|
|
129
|
+
}
|