@bongos/core 1.25.22 → 1.25.24

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.
@@ -12,7 +12,7 @@
12
12
  "surface": "builders",
13
13
  "title": "Studio",
14
14
  "states_read": ["pick","describe","make","waiting","result","result-own","failed","balance","balance-all","out"],
15
- "files_hash": "17d5a64433b6b71c",
15
+ "files_hash": "cdbab8f0c6d2bbad",
16
16
  "reading_hash": "d9e0e85bcee4aff4",
17
17
  "counts": {"lines":106,"placed":41,"shared":7,"unplaced":58},
18
18
  "omitted": {"data":17},
@@ -131,7 +131,7 @@
131
131
  "surface": "builders",
132
132
  "title": "Repo Atlas",
133
133
  "states_read": ["map","truth","detail","index","out"],
134
- "files_hash": "18b32dbea6044edd",
134
+ "files_hash": "a3fbc9538459ba45",
135
135
  "reading_hash": "6934dead335b2507",
136
136
  "counts": {"lines":25,"placed":14,"shared":7,"unplaced":4},
137
137
  "omitted": {"data":5},
@@ -169,7 +169,7 @@
169
169
  "surface": "builders",
170
170
  "title": "Blockers",
171
171
  "states_read": ["default"],
172
- "files_hash": "0bead21c9c6eefd8",
172
+ "files_hash": "9c5ef517607cd4d5",
173
173
  "reading_hash": "60d73d854ced958a",
174
174
  "counts": {"lines":36,"placed":17,"shared":7,"unplaced":12},
175
175
  "omitted": {"data":51},
@@ -218,7 +218,7 @@
218
218
  "surface": "builders",
219
219
  "title": "Board Room",
220
220
  "states_read": ["room","out","sitting-meta","objection-form"],
221
- "files_hash": "ddd26bb2c9637a8d",
221
+ "files_hash": "2919ddd4ce80e80d",
222
222
  "reading_hash": "0260b797b8dc1526",
223
223
  "counts": {"lines":52,"placed":21,"shared":7,"unplaced":24},
224
224
  "omitted": {"data":17},
@@ -283,7 +283,7 @@
283
283
  "surface": "builders",
284
284
  "title": "The city",
285
285
  "states_read": ["city","fullscreen","focus","pins","living","card","card-ask"],
286
- "files_hash": "e16f8bc66b6be0eb",
286
+ "files_hash": "73fe2f345e054222",
287
287
  "reading_hash": "277096d903879a57",
288
288
  "counts": {"lines":26,"placed":9,"shared":6,"unplaced":11},
289
289
  "omitted": {"data":7},
@@ -322,7 +322,7 @@
322
322
  "surface": "builders",
323
323
  "title": "Collab",
324
324
  "states_read": ["board","out"],
325
- "files_hash": "b48ecfa0a9e41156",
325
+ "files_hash": "4721415525b273b8",
326
326
  "reading_hash": "e6452bf92231656f",
327
327
  "counts": {"lines":82,"placed":36,"shared":6,"unplaced":40},
328
328
  "omitted": {"data":23},
@@ -417,7 +417,7 @@
417
417
  "surface": "builders",
418
418
  "title": "Commands",
419
419
  "states_read": ["in","out"],
420
- "files_hash": "3b6d7efe47c293b1",
420
+ "files_hash": "0c738f2e2ca48abf",
421
421
  "reading_hash": "ecc452689a8ee9d7",
422
422
  "counts": {"lines":71,"placed":49,"shared":7,"unplaced":15},
423
423
  "omitted": {"data":177},
@@ -501,7 +501,7 @@
501
501
  "surface": "builders",
502
502
  "title": "Copy desk",
503
503
  "states_read": ["queue","out","search","composer","closer","proposer"],
504
- "files_hash": "74d3cc01cc3a2bd3",
504
+ "files_hash": "830b92d08ea0a782",
505
505
  "reading_hash": "3819ef6fa8f6fb7c",
506
506
  "counts": {"lines":72,"placed":36,"shared":7,"unplaced":29},
507
507
  "omitted": {"data":94},
@@ -586,7 +586,7 @@
586
586
  "surface": "builders",
587
587
  "title": "Deploy",
588
588
  "states_read": ["work","out"],
589
- "files_hash": "e9d6f8f7acf84e4f",
589
+ "files_hash": "69f45e766f0a41a1",
590
590
  "reading_hash": "3770e8b2fa56bee1",
591
591
  "counts": {"lines":14,"placed":5,"shared":7,"unplaced":2},
592
592
  "omitted": {"data":5},
@@ -613,7 +613,7 @@
613
613
  "surface": "builders",
614
614
  "title": "The sky",
615
615
  "states_read": ["tour","sky","wells","ledger","full","full-back","out"],
616
- "files_hash": "687182dbc5fc4bc1",
616
+ "files_hash": "f6117c7d0796af5f",
617
617
  "reading_hash": "4a879397a84631e3",
618
618
  "counts": {"lines":50,"placed":25,"shared":6,"unplaced":19},
619
619
  "omitted": {"data":10},
@@ -676,7 +676,7 @@
676
676
  "surface": "builders",
677
677
  "title": "Goals",
678
678
  "states_read": ["list","filters","cards","detail","dependencies","out","uat","uat-panel","author"],
679
- "files_hash": "1870a44ee98803c6",
679
+ "files_hash": "a0e2123adaeb8051",
680
680
  "reading_hash": "13a5d07b3804b627",
681
681
  "counts": {"lines":187,"placed":61,"shared":7,"unplaced":119},
682
682
  "omitted": {"data":315},
@@ -876,7 +876,7 @@
876
876
  "surface": "builders",
877
877
  "title": "Government",
878
878
  "states_read": ["constitution","out","permissions","board","constitution-tab"],
879
- "files_hash": "51c22aab6725cfe5",
879
+ "files_hash": "f569a5c639f66f09",
880
880
  "reading_hash": "37c6878d60447fd6",
881
881
  "counts": {"lines":65,"placed":27,"shared":7,"unplaced":31},
882
882
  "omitted": {"data":276},
@@ -954,7 +954,7 @@
954
954
  "surface": "builders",
955
955
  "title": "Builders' Hall",
956
956
  "states_read": ["home","out","founding","genesis","decide","demo","votes"],
957
- "files_hash": "d403a1522c33b4af",
957
+ "files_hash": "d43337a7032689aa",
958
958
  "reading_hash": "c5f4986bd90e2a2a",
959
959
  "counts": {"lines":29,"placed":8,"shared":8,"unplaced":13},
960
960
  "omitted": {"data":4},
@@ -996,7 +996,7 @@
996
996
  "surface": "builders",
997
997
  "title": "Idea",
998
998
  "states_read": ["record","missing"],
999
- "files_hash": "8ec5c9ceeb7f717f",
999
+ "files_hash": "5f1c393ed14ae358",
1000
1000
  "reading_hash": "f7d644748c87e426",
1001
1001
  "counts": {"lines":52,"placed":25,"shared":8,"unplaced":19},
1002
1002
  "omitted": {"data":25},
@@ -1061,7 +1061,7 @@
1061
1061
  "surface": "builders",
1062
1062
  "title": "Ideas",
1063
1063
  "states_read": ["compose","full","develop"],
1064
- "files_hash": "b450280b85a2cc13",
1064
+ "files_hash": "145e8d36130c8f1f",
1065
1065
  "reading_hash": "a62c05dcef3bf87f",
1066
1066
  "counts": {"lines":68,"placed":34,"shared":7,"unplaced":27},
1067
1067
  "omitted": {"data":118},
@@ -1142,7 +1142,7 @@
1142
1142
  "surface": "builders",
1143
1143
  "title": "Market Watch",
1144
1144
  "states_read": ["desk","settings","out"],
1145
- "files_hash": "1d4fcc358272b052",
1145
+ "files_hash": "4141ab24056f355e",
1146
1146
  "reading_hash": "30512dda207b5ea6",
1147
1147
  "counts": {"lines":23,"placed":11,"shared":7,"unplaced":5},
1148
1148
  "omitted": {"data":5},
@@ -1178,7 +1178,7 @@
1178
1178
  "surface": "builders",
1179
1179
  "title": "Market Watch",
1180
1180
  "states_read": ["dossier","out","propose","correct","filtered"],
1181
- "files_hash": "12b90cad4fb01221",
1181
+ "files_hash": "168f1eb88a61e13e",
1182
1182
  "reading_hash": "129bff28c4e4ed6d",
1183
1183
  "counts": {"lines":24,"placed":12,"shared":7,"unplaced":5},
1184
1184
  "omitted": {"data":5},
@@ -1215,7 +1215,7 @@
1215
1215
  "surface": "builders",
1216
1216
  "title": "Market Watch rules",
1217
1217
  "states_read": ["in","scoring","names","propose","out"],
1218
- "files_hash": "c61460faaefc4a66",
1218
+ "files_hash": "5408691ae4f6bf4b",
1219
1219
  "reading_hash": "ca0c62e8dce51c8b",
1220
1220
  "counts": {"lines":36,"placed":12,"shared":7,"unplaced":17},
1221
1221
  "omitted": {"data":20},
@@ -1264,7 +1264,7 @@
1264
1264
  "surface": "builders",
1265
1265
  "title": "Modules",
1266
1266
  "states_read": ["browse","search-empty","lens","details","out"],
1267
- "files_hash": "97b566011430a4df",
1267
+ "files_hash": "7dd0737e655050e8",
1268
1268
  "reading_hash": "6a12e9306bba5622",
1269
1269
  "counts": {"lines":59,"placed":29,"shared":7,"unplaced":23},
1270
1270
  "omitted": {"data":107},
@@ -1336,7 +1336,7 @@
1336
1336
  "surface": "builders",
1337
1337
  "title": "Money",
1338
1338
  "states_read": ["money","hosting","out"],
1339
- "files_hash": "499e22b14807227c",
1339
+ "files_hash": "22c40cfbcdfd0a69",
1340
1340
  "reading_hash": "e355d5466b123e07",
1341
1341
  "counts": {"lines":83,"placed":28,"shared":7,"unplaced":48},
1342
1342
  "omitted": {"data":27},
@@ -1432,7 +1432,7 @@
1432
1432
  "surface": "builders",
1433
1433
  "title": "My agents",
1434
1434
  "states_read": ["desk","factory","saved","what-it-knows","speciality-walk","speciality-forms","nobody"],
1435
- "files_hash": "f38385f6e33a8b42",
1435
+ "files_hash": "87c92116f01b62b5",
1436
1436
  "reading_hash": "5347e0496b38727d",
1437
1437
  "counts": {"lines":100,"placed":33,"shared":7,"unplaced":60},
1438
1438
  "omitted": {"data":38},
@@ -1545,7 +1545,7 @@
1545
1545
  "surface": "builders",
1546
1546
  "title": "Primer",
1547
1547
  "states_read": ["in","toc-open","jump","out"],
1548
- "files_hash": "7eb8528d0fbd3e51",
1548
+ "files_hash": "47acee434c6cdb3c",
1549
1549
  "reading_hash": "85790bd421e5c387",
1550
1550
  "counts": {"lines":487,"placed":57,"shared":7,"unplaced":423},
1551
1551
  "omitted": {"data":18},
@@ -2045,7 +2045,7 @@
2045
2045
  "surface": "builders",
2046
2046
  "title": "Profile",
2047
2047
  "states_read": ["own","works","activity","yours","activity-artist","activity-artist-ideas","other","artist","artist-ideas","out"],
2048
- "files_hash": "9da57451b5f9b2e6",
2048
+ "files_hash": "0cbc2927f005a5d5",
2049
2049
  "reading_hash": "3ff8d703d17e8c2a",
2050
2050
  "counts": {"lines":232,"placed":84,"shared":7,"unplaced":141},
2051
2051
  "omitted": {"data":263},
@@ -2290,7 +2290,7 @@
2290
2290
  "surface": "builders",
2291
2291
  "title": "Project settings",
2292
2292
  "states_read": ["default"],
2293
- "files_hash": "955a2e4c2f6aa5a5",
2293
+ "files_hash": "fc09e96def6ea882",
2294
2294
  "reading_hash": "283df27d0d5bfc1b",
2295
2295
  "counts": {"lines":43,"placed":25,"shared":7,"unplaced":11},
2296
2296
  "omitted": {"data":33},
@@ -2346,7 +2346,7 @@
2346
2346
  "surface": "builders",
2347
2347
  "title": "Builders",
2348
2348
  "states_read": ["roster","artists","search","out"],
2349
- "files_hash": "42b228ce84b1a605",
2349
+ "files_hash": "cc82931525d4f791",
2350
2350
  "reading_hash": "665ac2e36339f5d3",
2351
2351
  "counts": {"lines":56,"placed":17,"shared":7,"unplaced":32},
2352
2352
  "omitted": {"data":137},
@@ -2415,7 +2415,7 @@
2415
2415
  "surface": "builders",
2416
2416
  "title": "Options",
2417
2417
  "states_read": ["account","access","preferences","install-reports","sound","update"],
2418
- "files_hash": "739d18345c5a8f19",
2418
+ "files_hash": "2c157a41c94a0b1e",
2419
2419
  "reading_hash": "a6d3194ed1b751ca",
2420
2420
  "counts": {"lines":163,"placed":104,"shared":7,"unplaced":52},
2421
2421
  "omitted": {"data":23},
@@ -2591,7 +2591,7 @@
2591
2591
  "surface": "builders",
2592
2592
  "title": "The street",
2593
2593
  "states_read": ["street","fullscreen","card","focus","here","inside-rules","inside-disputes","inside-people","inside-planning","inside-automation","inside-review","inside-release","inside-treasury","floor","amend","district","desk","desk-facts","desk-quiet","desk-people-builders","desk-people-tier","desk-disputes","desk-automation-goals","desk-release-core","desk-rules","desk-rules-category","desk-planning-priorities","desk-planning-ideas","desk-planning-blockers","pins","pins-pager","living","deck","deck-treasury","sitting","object","voted","admission","settled","blocker","blocker-more","report","report-more","core","core-more","recheck","recheck-more","idea","idea-more","queue","queue-more","automation","automation-more"],
2594
- "files_hash": "6d07f105e8450289",
2594
+ "files_hash": "132cd724c580d4c3",
2595
2595
  "reading_hash": "84dc42e85d9e23a3",
2596
2596
  "counts": {"lines":325,"placed":54,"shared":6,"unplaced":265},
2597
2597
  "omitted": {"data":241},
@@ -2929,7 +2929,7 @@
2929
2929
  "surface": "builders",
2930
2930
  "title": "Studio",
2931
2931
  "states_read": ["home","out","flow","flow-pick","status","words-offer","words-edit","reviews","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back","approvals-page"],
2932
- "files_hash": "2c1f851183201259",
2932
+ "files_hash": "66c949d568df1d11",
2933
2933
  "reading_hash": "a13406b48a9c7f7f",
2934
2934
  "counts": {"lines":51,"placed":29,"shared":7,"unplaced":15},
2935
2935
  "omitted": {"data":23},
@@ -2993,7 +2993,7 @@
2993
2993
  "surface": "builders",
2994
2994
  "title": "Task",
2995
2995
  "states_read": ["record","from-goal","missing"],
2996
- "files_hash": "1ac88cb702c5edc1",
2996
+ "files_hash": "111431221df21ab7",
2997
2997
  "reading_hash": "8dd803b6934e6388",
2998
2998
  "counts": {"lines":151,"placed":46,"shared":9,"unplaced":96},
2999
2999
  "omitted": {"data":111},
@@ -3157,7 +3157,7 @@
3157
3157
  "surface": "builders",
3158
3158
  "title": "Your thinking",
3159
3159
  "states_read": ["tour","sky","list","simple","full-idea","full","full-list","full-back","out"],
3160
- "files_hash": "ea12c65839037f10",
3160
+ "files_hash": "3c93bc1c3a43fbca",
3161
3161
  "reading_hash": "b73f848b46b0f9b8",
3162
3162
  "counts": {"lines":50,"placed":25,"shared":6,"unplaced":19},
3163
3163
  "omitted": {"data":10},
@@ -3220,7 +3220,7 @@
3220
3220
  "surface": "builders",
3221
3221
  "title": "Tweak a page",
3222
3222
  "states_read": ["doc","typed","chrome","submitted","picking","out"],
3223
- "files_hash": "fef8f1200b685d88",
3223
+ "files_hash": "c10a03b61cbfb28b",
3224
3224
  "reading_hash": "f521f8d9a7147557",
3225
3225
  "counts": {"lines":26,"placed":18,"shared":2,"unplaced":6},
3226
3226
  "omitted": {"data":19},
@@ -3259,7 +3259,7 @@
3259
3259
  "surface": "builders",
3260
3260
  "title": "Watch",
3261
3261
  "states_read": ["board","out","operations","security","sessions","autobongos"],
3262
- "files_hash": "b080c12c3acfca50",
3262
+ "files_hash": "806a9a91245c2899",
3263
3263
  "reading_hash": "1961a0c06b9d8477",
3264
3264
  "counts": {"lines":72,"placed":33,"shared":7,"unplaced":32},
3265
3265
  "omitted": {"data":52},
@@ -3344,7 +3344,7 @@
3344
3344
  "surface": "builders",
3345
3345
  "title": "Tasks",
3346
3346
  "states_read": ["ready","in-progress","backlog","completed","filters-open","out","founding"],
3347
- "files_hash": "f075dc964e20faf5",
3347
+ "files_hash": "d68c93ff47873b62",
3348
3348
  "reading_hash": "e9b412d1ec59ceee",
3349
3349
  "counts": {"lines":122,"placed":49,"shared":7,"unplaced":66},
3350
3350
  "omitted": {"data":323},
@@ -30,7 +30,8 @@
30
30
  stage_tasks_unfinished: 'This stage still has unfinished tasks.',
31
31
  not_current_stage: 'That stage is already behind you.',
32
32
  legislation_not_passed: 'Legislation has to pass the Board Room first.',
33
- not_deciding: 'The plan is already settled.',
33
+ stage_closed: 'The Board Room has passed that stage, so its answers are fixed.',
34
+ stage_lock_unknown: 'The Board Room could not be read, so nothing was changed. Try again in a moment.',
34
35
  };
35
36
 
36
37
  // What saving the plan did to the government, when it was not settled in the same
@@ -99,9 +100,17 @@
99
100
 
100
101
  // ── decide ────────────────────────────────────────────────────────────────
101
102
 
103
+ // Task 1005107: the same form REVISES a saved plan — it opens with the founder's own
104
+ // answers, and saving the same plan again changes nothing on the server.
102
105
  function decideHtml(g, gov) {
106
+ var p = g.plan || null;
107
+ if (p && p.government && gov) gov = Object.assign({}, gov, { recommended: { key: p.government } });
108
+ if (p && p.expected_builders && gov) gov = Object.assign({}, gov, { headcount: p.expected_builders });
103
109
  var rows = g.stages.map(function (s) {
104
- var opts = DAY_CHOICES.map(function (d) {
110
+ // A saved length that is not one of the presets is kept as its own choice, so
111
+ // reopening the plan never quietly changes it (task 1005107).
112
+ var choices = DAY_CHOICES.indexOf(s.days) < 0 ? DAY_CHOICES.concat([s.days]).sort(function (x, y) { return x - y; }) : DAY_CHOICES;
113
+ var opts = choices.map(function (d) {
105
114
  return '<option value="' + d + '"' + (d === s.days ? ' selected' : '') + '>' + d + (d === 1 ? ' day' : ' days') + '</option>';
106
115
  }).join('');
107
116
  return '<li class="genesis__plan-row">'
@@ -110,22 +119,25 @@
110
119
  + '<label class="genesis__plan-len"><span class="sr-only">Length of ' + esc(s.label) + '</span>'
111
120
  + '<select data-days="' + esc(s.key) + '">' + opts + '</select></label></li>';
112
121
  }).join('');
113
- return '<p class="scroll__lede">Settle the plan and each stage becomes real tasks. '
114
- + 'Everything is preset to our recommendation, so one click is enough.</p>'
122
+ return (p
123
+ ? '<p class="scroll__lede">Change any of your answers. Due dates follow the new lengths; a new government goes to the board like any charter change.</p>'
124
+ : '<p class="scroll__lede">Settle the plan and each stage becomes real tasks. '
125
+ + 'Everything is preset to our recommendation, so one click is enough.</p>')
115
126
  + '<ol class="genesis__plan">' + rows + '</ol>'
116
127
  + '<div class="genesis__picks">'
117
128
  + governmentHtml(gov)
118
129
  + '<fieldset class="genesis__pick"><legend>How many passes</legend>'
119
- + radio('passes', '1', 'One', 'Each stage is decided once.', true)
120
- + radio('passes', '2', 'Two', 'Once now, and again when your next builders join.', false)
130
+ + radio('passes', '1', 'One', 'Each stage is decided once.', !p || p.passes !== 2)
131
+ + radio('passes', '2', 'Two', 'Once now, and again when your next builders join.', !!p && p.passes === 2)
121
132
  + '</fieldset>'
122
133
  + '<fieldset class="genesis__pick"><legend>Advisors</legend>'
123
- + radio('advisors', 'none', 'None for now', 'You can add advisors at any stage.', true)
124
- + radio('advisors', 'cbaas', 'Cloud Bongos advisors', 'Our consultants review each stage.', false)
134
+ + radio('advisors', 'none', 'None for now', 'You can add advisors at any stage.', !p || p.advisors !== 'cbaas')
135
+ + radio('advisors', 'cbaas', 'Cloud Bongos advisors', 'Our consultants review each stage.', !!p && p.advisors === 'cbaas')
125
136
  + '</fieldset>'
126
- + '<label class="genesis__check"><input type="checkbox" data-existing> It already exists, so gather what it has first</label>'
137
+ + '<label class="genesis__check"><input type="checkbox" data-existing' + (p && p.existing ? ' checked' : '') + '> It already exists, so gather what it has first</label>'
127
138
  + '</div>'
128
- + '<div class="genesis__doors"><button type="button" class="btn-accent" data-genesis-plan>Use this plan</button></div>';
139
+ + '<div class="genesis__doors"><button type="button" class="btn-accent" data-genesis-plan>' + (p ? 'Save the plan' : 'Use this plan') + '</button>'
140
+ + (p ? '<button type="button" class="btn-ghost" data-genesis-plan-cancel>Keep it as it was</button>' : '') + '</div>';
129
141
  }
130
142
 
131
143
  function radio(name, value, label, hint, checked) {
@@ -157,6 +169,47 @@
157
169
  + '</fieldset>';
158
170
  }
159
171
 
172
+ // ── changing a finished stage's answers (task 1005107) ─────────────────────
173
+ // The stage's own record (GET /founding/work/:stage), opened in place with the answers
174
+ // already given. Save sends only what changed; nothing changed sends nothing.
175
+ function stageEditorHtml(w) {
176
+ if (!w) return '';
177
+ var rows = (w.questions || []).map(function (q) {
178
+ var cur = q.answer && q.answer.state === 'answered' ? (q.answer.text || '') : '';
179
+ var field = q.choices
180
+ ? '<select data-answer="' + esc(q.id) + '"><option value=""' + (cur ? '' : ' selected') + '>Not answered</option>'
181
+ + q.choices.map(function (c) { return '<option value="' + esc(c.key) + '"' + (c.key === cur ? ' selected' : '') + '>' + esc(c.label) + '</option>'; }).join('') + '</select>'
182
+ : '<textarea rows="3" data-answer="' + esc(q.id) + '">' + esc(cur) + '</textarea>';
183
+ return '<label class="genesis__edit-q"><b>' + esc(q.ask) + '</b>' + field + '</label>';
184
+ }).join('');
185
+ return '<section class="genesis__edit" aria-label="Change the ' + esc(w.stage) + ' answers">'
186
+ + '<h3 class="genesis__now-h">Change the ' + esc(w.stage) + ' answers</h3>'
187
+ + '<p class="genesis__note">Changing them does not reopen the stage.</p>' + rows
188
+ + '<label class="genesis__edit-q"><b>In your own words</b><textarea rows="5" data-page>' + esc(w.page || '') + '</textarea></label>'
189
+ + '<div class="genesis__doors"><button type="button" class="btn-accent" data-genesis-stage-save>Save changes</button>'
190
+ + '<button type="button" class="btn-ghost" data-genesis-stage-cancel>Leave it as it was</button></div></section>';
191
+ }
192
+
193
+ // stageChanges(w, host) → the writes the edited form needs, only for what changed.
194
+ function stageChanges(w, host) {
195
+ var out = [];
196
+ (w.questions || []).forEach(function (q) {
197
+ var el = host.querySelector('[data-answer="' + q.id + '"]');
198
+ if (!el) return;
199
+ var was = q.answer && q.answer.state === 'answered' ? (q.answer.text || '') : '';
200
+ var now = String(el.value || '').trim();
201
+ if (now === was.trim()) return;
202
+ var path = '/founding/work/' + encodeURIComponent(w.stage) + '/answers/' + encodeURIComponent(q.id);
203
+ if (now) out.push(['PUT', path, { state: 'answered', text: now }]);
204
+ else if (q.answer) out.push(['DELETE', path, null]);
205
+ });
206
+ var page = host.querySelector('[data-page]');
207
+ if (page && String(page.value || '').trim() !== String(w.page || '').trim()) {
208
+ out.push(['PUT', '/founding/work/' + encodeURIComponent(w.stage) + '/page', { page: String(page.value || '') }]);
209
+ }
210
+ return out;
211
+ }
212
+
160
213
  // ── the stages ────────────────────────────────────────────────────────────
161
214
 
162
215
  function lifeHtml(g) {
@@ -207,9 +260,15 @@
207
260
  // buildings it raises, and for a stage that wakes no room, what it earns.
208
261
  + '<span>' + esc(gainsText(s)) + esc(due) + '</span>'
209
262
  + (s.state === 'later' && s.can_close ? '<span><button type="button" class="btn-ghost" data-genesis-close="' + esc(s.key) + '">Put to the board</button></span>' : '')
263
+ // Task 1005107: a finished stage stays editable unless the Board Room passed it.
264
+ + (s.state === 'done' ? (s.locked
265
+ ? '<span class="genesis__stage-fixed">' + esc('Fixed: ' + s.locked.reason) + '</span>'
266
+ : '<span><button type="button" class="btn-ghost" data-genesis-stage-edit="' + esc(s.key) + '">Change its answers</button></span>') : '')
210
267
  + '</span>'
211
268
  + '<span class="genesis__stage-st">' + esc(stateText(s)) + '</span></li>';
212
- }).join('') + '</ol>';
269
+ }).join('') + '</ol>'
270
+ // Task 1005107: the plan is never a trap — reopen it with the answers already given.
271
+ + (g.plan_editable && !g.demo ? '<div class="genesis__doors"><button type="button" class="btn-ghost" data-genesis-plan-edit>Change the plan</button></div>' : '');
213
272
  }
214
273
 
215
274
  // task 1005109: Copy prompt on each task still to do, so the founder pastes it into
@@ -382,9 +441,10 @@
382
441
  function render(host, state) {
383
442
  var g = state.genesis;
384
443
  if (!g) { host.hidden = true; return; }
385
- host.innerHTML = headHtml(g) + (g.deciding
386
- ? decideHtml(g, state.gov)
387
- : demoHtml(g) + lifeHtml(g) + votesHtml(g, state.viewer) + '<div class="genesis__grid">' + stagesHtml(g) + nowHtml(g, state.viewer) + '</div>');
444
+ host.innerHTML = headHtml(g) + (g.deciding || state.editingPlan
445
+ ? decideHtml(g.deciding ? Object.assign({}, g, { plan: null }) : g, state.gov)
446
+ : demoHtml(g) + lifeHtml(g) + votesHtml(g, state.viewer) + '<div class="genesis__grid">' + stagesHtml(g) + nowHtml(g, state.viewer) + '</div>'
447
+ + stageEditorHtml(state.stageWork));
388
448
  host.hidden = false;
389
449
  }
390
450
 
@@ -449,22 +509,44 @@
449
509
  if (!t || !host.contains(t)) return;
450
510
  if (t.hasAttribute('data-genesis-copy')) {
451
511
  copyPrompt(t, state);
512
+ } else if (t.hasAttribute('data-genesis-stage-edit')) {
513
+ act(send('GET', '/founding/work/' + encodeURIComponent(t.getAttribute('data-genesis-stage-edit'))).then(function (d) {
514
+ state.stageWork = d && d.work; render(host, state);
515
+ }));
516
+ } else if (t.hasAttribute('data-genesis-stage-cancel')) {
517
+ state.stageWork = null;
518
+ render(host, state);
519
+ } else if (t.hasAttribute('data-genesis-stage-save')) {
520
+ var writes = stageChanges(state.stageWork, host);
521
+ if (!writes.length) { state.stageWork = null; render(host, state); toast('Nothing changed.'); return; }
522
+ act(writes.reduce(function (p, w) { return p.then(function () { return send(w[0], w[1], w[2]); }); }, Promise.resolve())
523
+ .then(function () { state.stageWork = null; render(host, state); toast('Saved.'); }));
524
+ } else if (t.hasAttribute('data-genesis-plan-edit')) {
525
+ var exp = state.genesis && state.genesis.plan && state.genesis.plan.expected_builders;
526
+ act(loadGov(exp || null).then(function (gov) { state.gov = gov; state.editingPlan = true; render(host, state); }));
527
+ } else if (t.hasAttribute('data-genesis-plan-cancel')) {
528
+ state.editingPlan = false;
529
+ render(host, state);
452
530
  } else if (t.hasAttribute('data-genesis-plan')) {
453
531
  // The government picked here is filed as a charter amendment with the plan
454
532
  // (task 1004656). When the founder's one yes decides it, saving the plan is
455
533
  // that yes too, the same one-click fast-track the stage closes take.
456
534
  act(send('POST', '/founding/plan', planBody(host)).then(function (out) {
535
+ // A revision (task 1005107): say if nothing changed, and every change it could not carry.
536
+ if (out && out.revised === false) { state.editingPlan = false; render(host, state); toast('Nothing changed.'); return 'stay'; }
537
+ var held = !!(out && out.could_not && out.could_not.length);
538
+ if (held) toast(out.could_not.join(' '));
457
539
  var c = out && out.charter;
458
540
  if (c && c.state === 'sitting' && c.one_vote_decides && c.item_id) {
459
541
  return send('POST', '/government/board/items/' + encodeURIComponent(c.item_id) + '/votes', { direction: 'yes' })
460
542
  .catch(function () { return null; });
461
543
  }
462
544
  var said = charterNote(c);
463
- if (!said) return null;
545
+ if (!said) return held ? window.OTB.sleep(3500) : null;
464
546
  toast(said);
465
547
  // Give the sentence time to be read before the reload takes it away.
466
548
  return window.OTB.sleep(3500);
467
- }).then(function () { window.location.reload(); }));
549
+ }).then(function (r) { if (r !== 'stay') window.location.reload(); }));
468
550
  } else if (t.hasAttribute('data-genesis-close')) {
469
551
  // One call (task 1005121): where the founder's one yes decides, the server
470
552
  // closes the stage with it; otherwise it answers 202 with what the sitting
@@ -12,7 +12,8 @@
12
12
  // The index has three CLIENT-SIDE layers (task 2178 scope):
13
13
  // 1. Pages — read live from the sidebar shell.js rendered, so rank + module
14
14
  // gating come for free and can never drift from the nav. A hidden nav item
15
- // is a hidden destination. (Cosmetic only; the server still gates each page.)
15
+ // is a hidden destination, and so is a room asleep while the project is
16
+ // founding. (Cosmetic only; the server still gates each page.)
16
17
  // 2. Sections — the sub-destinations of the four pages that have them. These
17
18
  // cannot be read from another page's DOM, so they are declared below and
18
19
  // held to the real ids by tests/hall_palette.mjs.
@@ -145,9 +146,15 @@
145
146
  var searchCache = {}; // query (trimmed+lowercased) -> raw hits[], this OPEN only
146
147
 
147
148
  function esc(s) { return window.OTB.escapeHtml(s); }
149
+ // A nav item the sidebar does not show is not a destination: hidden by its gate, or
150
+ // asleep while the project is founding (task 1005285). The sleeping mark is the
151
+ // shell's, stamped from the server's /me.founding_mode.asleep, never decided here,
152
+ // and the server refuses the page as well (src/bongos/founding-page-gate.js).
153
+ function offered(el) {
154
+ return !!(el && !el.hidden && !(el.classList && el.classList.contains('nav-item--asleep')));
155
+ }
148
156
  function visible(id) {
149
- var el = document.getElementById(id);
150
- return !!(el && !el.hidden);
157
+ return offered(document.getElementById(id));
151
158
  }
152
159
 
153
160
  // Pages, straight from the rendered sidebar. Skips the external API-docs link's
@@ -160,7 +167,7 @@
160
167
  function pageEntries() {
161
168
  var out = [];
162
169
  document.querySelectorAll('#app-sidebar .nav-item').forEach(function (a) {
163
- if (a.hidden) return;
170
+ if (!offered(a)) return;
164
171
  var label = (a.querySelector('.nav-item__label') || {}).textContent || '';
165
172
  if (!label) return;
166
173
  out.push({
@@ -29,3 +29,9 @@ work-founding.states.json renders an ordinary hall page with a founding /me (kit
29
29
  - The genesis home, the stage tasks and the "what's this?" destination belong to PS08 (task 1004423). The band links home until then.
30
30
  - The founding mark belongs to PS10 (task 1004424).
31
31
  - Starting founding on a new project and moving its stage is `setFoundingMode`, on the onboarding port, and PS08 drives it. Nothing in this task writes it.
32
+
33
+ ## The classic hall wears all three genesis behaviours (task 1005285)
34
+
35
+ Since task 1005112 an asleep room is **hidden, not dimmed**, and its page is refused (`src/bongos/founding-page-gate.js` redirects home with `?asleep=<room>&opens=<stage>`, and the shell says which stage opens it); the "cosmetic, nothing enforced" line above is history. The owner asked (2026-11-13) that the classic hall get the same three genesis behaviours as the game. Two were already shared code: the stage checklist (done / open / locked, and what a locked task waits on, from `shapeGenesis`) and Copy prompt on each open task are the Home banner card `genesis-home.js`, which both views load. The gap was the **jump list**: `palette.js` skipped only a nav item with the `hidden` attribute, so Ctrl/Cmd-K still offered Tasks, Goals, Sky, Collab and Builders, and the Tasks tabs, while they slept. It now treats `.nav-item--asleep` (the shell's mark, stamped from `/me.founding_mode.asleep`) as not a destination, for pages and for their sections; it never works out which rooms sleep itself. `tests/hall_palette.mjs` holds it against the real `shapeFoundingMode`.
36
+
37
+ **To walk it:** `node scripts/hall-preview/server.js --fixture-me --founding scope` (the `hall-preview-founding` launch entry). `/me.founding_mode` is the real `shapeFoundingMode`, `GET /founding/genesis` the real `shapeGenesis` over `scripts/hall-preview/fixtures/founding__genesis__tasks.json`, and a sleeping room's page answers through the real `foundingPageGate`.