@bongos/core 1.21.9 → 1.21.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +35 -25
- package/docs/copy-inventory.md +23 -38
- package/docs/copy-registry.json +60 -207
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +14 -2
- package/docs/page-readings.json +188 -33
- package/modules/hall-ui/public/street-draw.js +14 -8
- package/modules/hall-ui/public/street-inside.js +568 -0
- package/modules/hall-ui/public/street.css +132 -3
- package/modules/hall-ui/public/street.html +82 -7
- package/modules/hall-ui/public/street.js +327 -9
- package/modules/hall-ui/public/street.states.json +339 -18
- package/modules/hall-ui/records/governor-street.md +21 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/gds/copy-inventory.js +24 -7
- package/src/module-api.js +1 -1
- package/tests/copy_inventory.mjs +62 -0
- package/tests/hall_street.mjs +1 -1
- package/tests/hall_street_inside.mjs +519 -0
|
@@ -1,43 +1,364 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_": "THE STREET (task 1004525, goal 1000125) through modules/ui-design/kit/render.js. The page draws GET /government/docket, GET /goals, GET /goals/rollups and the viewer's GET /builders/:id/earnings; against the kit's own stub none exists, so every state renders the bare street (the nine civic buildings, no districts, no pins) with the readings saying the docket could not be read: a real state the floors must hold in. To look at the populated street, run it against the hall-preview harness, whose government__docket.json fixture carries the reference design's seven sample matters (3 need you, 2 moving, 2 settled) and whose goals fixtures carry the open goals:\n\n node scripts/hall-preview/server.js --port 4625 --fixture-me\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/street.states.json --base-in http://localhost:4625 --base-out http://localhost:4625\n\nThe page follows the OS mode until the switch is pressed (then the hall's own 'hall-theme' preference), so the kit's dark/light emulation renders both modes.",
|
|
2
|
+
"_": "THE STREET (task 1004525, goal 1000125) and inside every building and district (task 1004526) through modules/ui-design/kit/render.js. The page draws GET /government/docket, GET /goals, GET /goals/rollups and the viewer's GET /builders/:id/earnings; against the kit's own stub none exists, so every state renders the bare street (the nine civic buildings, no districts, no pins) with the readings saying the docket could not be read: a real state the floors must hold in. To look at the populated street, run it against the hall-preview harness, whose government__docket.json fixture carries the reference design's seven sample matters (3 need you, 2 moving, 2 settled) and whose goals fixtures carry the open goals:\n\n node scripts/hall-preview/server.js --port 4625 --fixture-me\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/street.states.json --base-in http://localhost:4625 --base-out http://localhost:4625\n\nThe page follows the OS mode until the switch is pressed (then the hall's own 'hall-theme' preference), so the kit's dark/light emulation renders both modes.",
|
|
3
3
|
"page": "/builders/street",
|
|
4
4
|
"surface": "hall-ui",
|
|
5
|
-
"stub": {
|
|
5
|
+
"stub": {
|
|
6
|
+
"prefix": "/builders/"
|
|
7
|
+
},
|
|
6
8
|
"modeQuery": false,
|
|
7
|
-
"ignoreRequests": [
|
|
8
|
-
|
|
9
|
+
"ignoreRequests": [
|
|
10
|
+
"/api/(gds|bongos)/",
|
|
11
|
+
"fonts\\.g(oogleapis|static)\\.com"
|
|
12
|
+
],
|
|
13
|
+
"ignoreConsole": [
|
|
14
|
+
"/api/(gds|bongos)/",
|
|
15
|
+
"\\b401\\b",
|
|
16
|
+
"\\b403\\b",
|
|
17
|
+
"\\b404\\b",
|
|
18
|
+
"Unauthorized",
|
|
19
|
+
"Forbidden",
|
|
20
|
+
"Not Found",
|
|
21
|
+
"load failed",
|
|
22
|
+
"fonts\\.g(oogleapis|static)\\.com"
|
|
23
|
+
],
|
|
9
24
|
"states": {
|
|
10
25
|
"street": {
|
|
11
26
|
"auth": true,
|
|
12
27
|
"_": "The street: the header, the buildings in the order work moves with their names, state lines and group brackets, the pins, and the six readings.",
|
|
13
|
-
"actions": [
|
|
14
|
-
|
|
28
|
+
"actions": [
|
|
29
|
+
[
|
|
30
|
+
"wait",
|
|
31
|
+
900
|
|
32
|
+
]
|
|
33
|
+
],
|
|
34
|
+
"expect": {
|
|
35
|
+
"visible": [
|
|
36
|
+
"#streetBoard",
|
|
37
|
+
"#streetSigns",
|
|
38
|
+
"#streetMode",
|
|
39
|
+
"#streetHome"
|
|
40
|
+
],
|
|
41
|
+
"href": [
|
|
42
|
+
[
|
|
43
|
+
"#streetHome",
|
|
44
|
+
"/builders/city"
|
|
45
|
+
]
|
|
46
|
+
]
|
|
47
|
+
}
|
|
15
48
|
},
|
|
16
49
|
"card": {
|
|
17
50
|
"auth": true,
|
|
18
51
|
"_": "A pin pressed: the matter's short card over the street.",
|
|
19
|
-
"actions": [
|
|
20
|
-
|
|
52
|
+
"actions": [
|
|
53
|
+
[
|
|
54
|
+
"wait",
|
|
55
|
+
900
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
"click",
|
|
59
|
+
".street-pin"
|
|
60
|
+
],
|
|
61
|
+
[
|
|
62
|
+
"wait",
|
|
63
|
+
400
|
|
64
|
+
]
|
|
65
|
+
],
|
|
66
|
+
"expect": {
|
|
67
|
+
"visible": [
|
|
68
|
+
"#streetCard",
|
|
69
|
+
"#streetCardClose"
|
|
70
|
+
]
|
|
71
|
+
}
|
|
21
72
|
},
|
|
22
73
|
"switched": {
|
|
23
74
|
"auth": true,
|
|
24
75
|
"_": "The light/dark switch pressed once: the other mode, the street redrawn in it.",
|
|
25
|
-
"actions": [
|
|
26
|
-
|
|
76
|
+
"actions": [
|
|
77
|
+
[
|
|
78
|
+
"wait",
|
|
79
|
+
600
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"click",
|
|
83
|
+
"#streetMode"
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
"wait",
|
|
87
|
+
400
|
|
88
|
+
]
|
|
89
|
+
],
|
|
90
|
+
"expect": {
|
|
91
|
+
"visible": [
|
|
92
|
+
"#streetBoard",
|
|
93
|
+
"#streetSigns"
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"focus": {
|
|
98
|
+
"auth": true,
|
|
99
|
+
"_": "Keyboard: the wordmark back to the city focused, its ring drawn.",
|
|
100
|
+
"actions": [
|
|
101
|
+
[
|
|
102
|
+
"wait",
|
|
103
|
+
600
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
"focus",
|
|
107
|
+
"#streetHome"
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
"wait",
|
|
111
|
+
100
|
|
112
|
+
]
|
|
113
|
+
],
|
|
114
|
+
"expect": {
|
|
115
|
+
"activeId": "streetHome"
|
|
116
|
+
}
|
|
27
117
|
},
|
|
28
118
|
"here": {
|
|
29
119
|
"auth": true,
|
|
30
|
-
"_": "Arrived through a door: the address names the Charter, so its
|
|
120
|
+
"_": "Arrived through a door: the address names the Charter, so the street gives way to the Charter in section (every floor, its sign, the lift at the chosen floor) and its panel.",
|
|
31
121
|
"url": "/builders/street#building=charter",
|
|
32
|
-
"actions": [
|
|
33
|
-
|
|
122
|
+
"actions": [
|
|
123
|
+
[
|
|
124
|
+
"wait",
|
|
125
|
+
900
|
|
126
|
+
]
|
|
127
|
+
],
|
|
128
|
+
"expect": {
|
|
129
|
+
"visible": [
|
|
130
|
+
"#streetInside",
|
|
131
|
+
"#insideName",
|
|
132
|
+
"#insideLift",
|
|
133
|
+
"#insideBack",
|
|
134
|
+
"#streetSigns"
|
|
135
|
+
],
|
|
136
|
+
"href": [
|
|
137
|
+
[
|
|
138
|
+
"#insideBack",
|
|
139
|
+
"/builders/street"
|
|
140
|
+
]
|
|
141
|
+
]
|
|
142
|
+
}
|
|
34
143
|
},
|
|
35
|
-
"
|
|
144
|
+
"inside-rules": {
|
|
36
145
|
"auth": true,
|
|
37
|
-
"_": "
|
|
38
|
-
"
|
|
39
|
-
"
|
|
146
|
+
"_": "Inside rules: its floors in section, its panel, its record.",
|
|
147
|
+
"url": "/builders/street#building=rules",
|
|
148
|
+
"actions": [
|
|
149
|
+
[
|
|
150
|
+
"wait",
|
|
151
|
+
900
|
|
152
|
+
]
|
|
153
|
+
],
|
|
154
|
+
"expect": {
|
|
155
|
+
"visible": [
|
|
156
|
+
"#streetInside",
|
|
157
|
+
"#insideName",
|
|
158
|
+
"#insidePanel"
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"inside-disputes": {
|
|
163
|
+
"auth": true,
|
|
164
|
+
"_": "Inside disputes: its floors in section, its panel, its record.",
|
|
165
|
+
"url": "/builders/street#building=disputes",
|
|
166
|
+
"actions": [
|
|
167
|
+
[
|
|
168
|
+
"wait",
|
|
169
|
+
900
|
|
170
|
+
]
|
|
171
|
+
],
|
|
172
|
+
"expect": {
|
|
173
|
+
"visible": [
|
|
174
|
+
"#streetInside",
|
|
175
|
+
"#insideName",
|
|
176
|
+
"#insidePanel"
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"inside-people": {
|
|
181
|
+
"auth": true,
|
|
182
|
+
"_": "Inside people: its floors in section, its panel, its record.",
|
|
183
|
+
"url": "/builders/street#building=people",
|
|
184
|
+
"actions": [
|
|
185
|
+
[
|
|
186
|
+
"wait",
|
|
187
|
+
900
|
|
188
|
+
]
|
|
189
|
+
],
|
|
190
|
+
"expect": {
|
|
191
|
+
"visible": [
|
|
192
|
+
"#streetInside",
|
|
193
|
+
"#insideName",
|
|
194
|
+
"#insidePanel"
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"inside-planning": {
|
|
199
|
+
"auth": true,
|
|
200
|
+
"_": "Inside planning: its floors in section, its panel, its record.",
|
|
201
|
+
"url": "/builders/street#building=planning",
|
|
202
|
+
"actions": [
|
|
203
|
+
[
|
|
204
|
+
"wait",
|
|
205
|
+
900
|
|
206
|
+
]
|
|
207
|
+
],
|
|
208
|
+
"expect": {
|
|
209
|
+
"visible": [
|
|
210
|
+
"#streetInside",
|
|
211
|
+
"#insideName",
|
|
212
|
+
"#insidePanel"
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"inside-automation": {
|
|
217
|
+
"auth": true,
|
|
218
|
+
"_": "Inside automation: its floors in section, its panel, its record.",
|
|
219
|
+
"url": "/builders/street#building=automation",
|
|
220
|
+
"actions": [
|
|
221
|
+
[
|
|
222
|
+
"wait",
|
|
223
|
+
900
|
|
224
|
+
]
|
|
225
|
+
],
|
|
226
|
+
"expect": {
|
|
227
|
+
"visible": [
|
|
228
|
+
"#streetInside",
|
|
229
|
+
"#insideName",
|
|
230
|
+
"#insidePanel"
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"inside-review": {
|
|
235
|
+
"auth": true,
|
|
236
|
+
"_": "Inside review: its floors in section, its panel, its record.",
|
|
237
|
+
"url": "/builders/street#building=review",
|
|
238
|
+
"actions": [
|
|
239
|
+
[
|
|
240
|
+
"wait",
|
|
241
|
+
900
|
|
242
|
+
]
|
|
243
|
+
],
|
|
244
|
+
"expect": {
|
|
245
|
+
"visible": [
|
|
246
|
+
"#streetInside",
|
|
247
|
+
"#insideName",
|
|
248
|
+
"#insidePanel"
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"inside-release": {
|
|
253
|
+
"auth": true,
|
|
254
|
+
"_": "Inside release: its floors in section, its panel, its record.",
|
|
255
|
+
"url": "/builders/street#building=release",
|
|
256
|
+
"actions": [
|
|
257
|
+
[
|
|
258
|
+
"wait",
|
|
259
|
+
900
|
|
260
|
+
]
|
|
261
|
+
],
|
|
262
|
+
"expect": {
|
|
263
|
+
"visible": [
|
|
264
|
+
"#streetInside",
|
|
265
|
+
"#insideName",
|
|
266
|
+
"#insidePanel"
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
"inside-treasury": {
|
|
271
|
+
"auth": true,
|
|
272
|
+
"_": "Inside treasury: its floors in section, its panel, its record.",
|
|
273
|
+
"url": "/builders/street#building=treasury",
|
|
274
|
+
"actions": [
|
|
275
|
+
[
|
|
276
|
+
"wait",
|
|
277
|
+
900
|
|
278
|
+
]
|
|
279
|
+
],
|
|
280
|
+
"expect": {
|
|
281
|
+
"visible": [
|
|
282
|
+
"#streetInside",
|
|
283
|
+
"#insideName",
|
|
284
|
+
"#insidePanel"
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
"floor": {
|
|
289
|
+
"auth": true,
|
|
290
|
+
"_": "A floor picked: the lift slides to it, its frame and sign turn orange, and its block re-enters with the sign large.",
|
|
291
|
+
"url": "/builders/street#building=people",
|
|
292
|
+
"actions": [
|
|
293
|
+
[
|
|
294
|
+
"wait",
|
|
295
|
+
900
|
|
296
|
+
],
|
|
297
|
+
[
|
|
298
|
+
"click",
|
|
299
|
+
".inside-floor[data-floor=\"0\"]"
|
|
300
|
+
],
|
|
301
|
+
[
|
|
302
|
+
"wait",
|
|
303
|
+
900
|
|
304
|
+
]
|
|
305
|
+
],
|
|
306
|
+
"expect": {
|
|
307
|
+
"visible": [
|
|
308
|
+
"#insideOpenB"
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
"amend": {
|
|
313
|
+
"auth": true,
|
|
314
|
+
"_": "Change how this works pressed: it says, in words, that drafting an amendment from here is not built yet (task 1004530).",
|
|
315
|
+
"url": "/builders/street#building=charter",
|
|
316
|
+
"actions": [
|
|
317
|
+
[
|
|
318
|
+
"wait",
|
|
319
|
+
900
|
|
320
|
+
],
|
|
321
|
+
[
|
|
322
|
+
"click",
|
|
323
|
+
"#insideAmend"
|
|
324
|
+
],
|
|
325
|
+
[
|
|
326
|
+
"wait",
|
|
327
|
+
200
|
|
328
|
+
]
|
|
329
|
+
],
|
|
330
|
+
"expect": {
|
|
331
|
+
"visible": [
|
|
332
|
+
"#insideAmendNote"
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
"district": {
|
|
337
|
+
"auth": true,
|
|
338
|
+
"_": "Inside a district: the goal's tasks as buildings on a road, shape the craft, stage the status, label the kind.",
|
|
339
|
+
"url": "/builders/street#district=25",
|
|
340
|
+
"actions": [
|
|
341
|
+
[
|
|
342
|
+
"wait",
|
|
343
|
+
1200
|
|
344
|
+
]
|
|
345
|
+
],
|
|
346
|
+
"expect": {
|
|
347
|
+
"visible": [
|
|
348
|
+
"#streetInside",
|
|
349
|
+
"#insideDName",
|
|
350
|
+
"#insideLegend"
|
|
351
|
+
]
|
|
352
|
+
}
|
|
40
353
|
}
|
|
41
354
|
},
|
|
42
|
-
"reducedMotion": {
|
|
355
|
+
"reducedMotion": {
|
|
356
|
+
"auth": true,
|
|
357
|
+
"actions": [
|
|
358
|
+
[
|
|
359
|
+
"wait",
|
|
360
|
+
600
|
|
361
|
+
]
|
|
362
|
+
]
|
|
363
|
+
}
|
|
43
364
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# The Governor City's street — /street, the six readings, and the
|
|
1
|
+
# The Governor City's street — /street, the six readings, and the interiors behind its doors (tasks 1004525, 1004526)
|
|
2
2
|
|
|
3
3
|
**R03 of goal 1000125.** Built 1:1 on the street view of the reference design [`docs/design/mocks/governor-city/Street.dc.html`](../../../docs/design/mocks/governor-city/README.md): one front-on row in the order work moves under five group brackets, a name and one state line under every building, pins with their labels always showing, work queued at Review as crates by its door, the header (wordmark back to the city, needs you, moving, your share this month, the light/dark switch) and the six readings along the bottom. The home city (`/city`, task 1004524) links here from start governing.
|
|
4
4
|
|
|
@@ -9,6 +9,25 @@ What it settled:
|
|
|
9
9
|
- **Standalone, like the city.** No hall sidebar or top bar; it is the second entry in `tests/hall_audit.mjs`'s `STANDALONE_EXEMPT`, with the city's reason. It still loads `style.css` and reads and writes the hall's own `hall-theme`.
|
|
10
10
|
- **The artboard is the street band.** The prototype's 1440 x 900 board less its 64 px header and 128 px footer, which the page lays out as real rows; `street.js` scales the 1440 x 708 band to the window, and on a phone keeps it near full size and lets the street scroll sideways inside its own window, so a pin stays a pin. The header fits the 80 px top-bar floor at 390 and 320 by going to two rows, its three figures as their own sideways strip.
|
|
11
11
|
- **Real data where the prototype had samples.** One district per open goal (up to eight plots; past that seven stand and the eighth is a staked lot that opens the goals page), each goal's tasks drawn in proportion (built, scaffold, the prototype's `ready` slab), Review held while any source that stands in it can be read, its open matters as crates and the dashed "waiting for a tester" count pin, a reading off drawn as a dash and its reason. The full list is the header of `street-draw.js`.
|
|
12
|
-
- **Every building and district is a door** to `/street#building=<key>` or `/street#district=<goal id>`, where
|
|
12
|
+
- **Every building and district is a door** to `/street#building=<key>` or `/street#district=<goal id>`, where its interior opens in place of the street (below). A pin opens the matter's short card (task 1004528 makes it act); its link is offered only for an on-site path.
|
|
13
13
|
|
|
14
14
|
Tests: `tests/hall_street.mjs` holds the kit, the row, the pins, the doors and the crates equal to the prototype by running its own `Component` class beside `street-draw.js` in both modes, then the docket rules and the page itself in a vm. The states file is `public/street.states.json`; render it against the hall-preview harness, whose `government__docket.json` fixture carries the seven sample matters.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Inside every building and district (task 1004526, R04)
|
|
18
|
+
|
|
19
|
+
Built 1:1 on `buildingView()` and `districtView()` of the same prototype. The interior is a view of this page, not a page of its own: when the address names a building or a district, `#streetInside` replaces the street band, and the header and the six readings stay (the reading for that building is marked).
|
|
20
|
+
|
|
21
|
+
Files: `street-inside.js` (`window.GovInside`, node-require-safe, pure): the prototype's `crown()`, `workItem()`, `floorSymbol()`, `symbolPath()` (all forty symbols) and the section drawing itself, verbatim, plus the real-data adapters. `street.js` builds the nodes; `street.css` carries the interior's styles under the `inside-` prefix.
|
|
22
|
+
|
|
23
|
+
- **The building in section.** Every storey a real floor (slab, cut walls with glazing, three lamps, a partition with a doorway, the framed sign with the floor's symbol, its name and state lettered on the wall, its count, its level number), dark empty floors up to the building's capacity, the crown per building, the lift in its shaft, the orange frame and orange sign on the chosen floor, and the annex lot once the building is full. An unheld Review is the dashed ghost (`GovStreet.reviewHeldOf()`, so the street and the interior agree).
|
|
24
|
+
- **The right panel.** Name and what it holds, who holds it (seat chips), how it decides (the rule glyph), **change how this works**, the fill meter with its growth line, on the table here, the chosen floor with its sign large, and the record as monthly filing drawers.
|
|
25
|
+
- **Floors are the prototype's structure; a number appears only when the docket holds it.** `GovInside.PLAN` keeps each building's floors, order and capacity. A floor bound to a docket source shows that source's open matters at this building (count, line, needs you, the lines); one bound to a reading shows its figure; Planning's Goals floor counts the open goals. Every other floor says "not recorded yet" on the wall, lettered faint, with no number. A source that is off, coming, not yours or unreadable says which, never a figure. Filling every floor with real data is task 1004527, through `floorFor()` and `PLAN`.
|
|
26
|
+
- **Who holds it.** The docket names no holders yet (task 1004529), so the seat is an empty dashed chip and says "who holds it is not set on this project yet". The rule is the one the building's open matters are decided by, else the design's default, which the words call "by default". `holderOf()` reads a docket building's `holders` / `rule` / `who` first, so 1004529 lands without touching the drawing.
|
|
27
|
+
- **The lift and the flip.** The lift is one node kept across draws, so picking a floor slides it by a CSS transform transition; the chosen floor's block is two blocks that take turns (`flipA` / `flipB`), so it re-enters on every pick. Both are dead under reduced motion.
|
|
28
|
+
- **Change how this works** is present and honest: pressed, it says drafting an amendment from here is not built yet (task 1004530 wires it).
|
|
29
|
+
- **On the table here** rows open the same short card a pin opens, through `openCard()`; Escape gives focus back to the row.
|
|
30
|
+
- **Districts.** The goal's tasks (`GET /tasks?goal_id=N`, read once per goal): shape from the discipline (tower engineer, studio artist, glass front UI, pavilion ideator; none is a tower), stage from the status (backlog and blocked a staked plot, ready a slab, active a scaffold, completed and confirmed built with a flag, shipped lit), label the kind; height from the estimate. Up to ten stand on the road, work in flight first; the rest are counted with a link to the goal. Each one opens its task.
|
|
31
|
+
- **Narrow.** Under 900 px the board becomes a column: the drawing in its own sideways strip (never scaled under 0.6, so a floor stays a 24 px target), then the panel.
|
|
32
|
+
|
|
33
|
+
Tests: `tests/hall_street_inside.mjs` runs the prototype's own `Component` beside `street-inside.js` on the prototype's sample floors and holds every building's section, panel bindings and every district equal to it in both modes, then the docket rules (no invented numbers) and the page in a vm (the persistent lift, the flip, the drawers, the amendment note, the card from a table row, back to the street, a district's tasks). The states file renders every building, a floor pick, the amendment note and a district.
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.11",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.21.
|
|
9
|
+
"version": "1.21.11",
|
|
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.
|
|
3
|
+
"version": "1.21.11",
|
|
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",
|
package/release-notes.json
CHANGED
|
@@ -8810,5 +8810,17 @@
|
|
|
8810
8810
|
"id": "1004529",
|
|
8811
8811
|
"text": "Each project can now set who decides what in each part of its government: the charter, rules, disputes, people, planning, automation, review, release and treasury. For each part it names who decides and how: one person decides"
|
|
8812
8812
|
}
|
|
8813
|
+
],
|
|
8814
|
+
"1.21.10": [
|
|
8815
|
+
{
|
|
8816
|
+
"id": "1004545",
|
|
8817
|
+
"text": "The list of every piece of on-screen text now comes out the same on a Windows computer as on the build server, so updating it on Windows no longer breaks the automatic checks. Notes the authors left inside page source are no l"
|
|
8818
|
+
}
|
|
8819
|
+
],
|
|
8820
|
+
"1.21.11": [
|
|
8821
|
+
{
|
|
8822
|
+
"id": "1004526",
|
|
8823
|
+
"text": "Every building on the governor's street now opens. Step through a door and the building appears in section, drawn exactly like the prototype: each floor a real storey with its sign, name and state on the wall, dark empty floor"
|
|
8824
|
+
}
|
|
8813
8825
|
]
|
|
8814
8826
|
}
|
|
@@ -119,8 +119,12 @@ function lineAt(starts, index) {
|
|
|
119
119
|
|
|
120
120
|
// Does this look like prose a person reads, rather than code that happens to be a
|
|
121
121
|
// string? Conservative on purpose — a false positive costs an artist's attention.
|
|
122
|
+
//
|
|
123
|
+
// Measured with CRLF folded to LF: the length cap must give a multi-line run the
|
|
124
|
+
// same verdict on a Windows checkout as on CI's, or the committed registry differs
|
|
125
|
+
// by platform (task 1004545 — a 396-char run was 403 under CRLF and vanished).
|
|
122
126
|
function looksLikeCopy(raw) {
|
|
123
|
-
const s = String(raw).trim();
|
|
127
|
+
const s = String(raw).replace(/\r\n/g, '\n').trim();
|
|
124
128
|
if (s.length < 4 || s.length > 400) return false;
|
|
125
129
|
if (!/[A-Za-z]{2}/.test(s)) return false; // needs actual letters
|
|
126
130
|
if (!/\s/.test(s) && !/[.!?]$/.test(s)) return false; // one bare word is a token
|
|
@@ -155,12 +159,25 @@ function trimmedSpan(group, groupStart) {
|
|
|
155
159
|
return { start: groupStart + lead, end: groupStart + group.length - trail };
|
|
156
160
|
}
|
|
157
161
|
|
|
158
|
-
// Strip <script>/<style> bodies so their contents are not read
|
|
159
|
-
// Replaced with spaces of equal length so every line number
|
|
162
|
+
// Strip HTML comments and <script>/<style> bodies so their contents are not read
|
|
163
|
+
// as page text. Replaced with spaces of equal length so every line number — and
|
|
164
|
+
// every span copy-apply.js writes through — stays truthful.
|
|
165
|
+
//
|
|
166
|
+
// Comments are author notes, never something a visitor reads (task 1004545: a
|
|
167
|
+
// header comment's literal `<a>` opened a fake text node). ONE alternation, not
|
|
168
|
+
// three passes, so whichever construct opens first wins, as in a browser: a
|
|
169
|
+
// `<style>` named inside a comment cannot swallow the page up to the real
|
|
170
|
+
// `</style>`, and a `<!--` inside a script string cannot eat past `</script>`.
|
|
171
|
+
//
|
|
172
|
+
// A comment keeps its `<` and `>` and blanks only its inside: marker comments
|
|
173
|
+
// (`<!--apex-only:start-->`, `<!--brand-if:…-->`) split a sentence into segments
|
|
174
|
+
// the server shows or drops independently, so each segment must stay its own row
|
|
175
|
+
// with its own stable id — blanking the whole comment would fuse them.
|
|
160
176
|
function stripEmbedded(html) {
|
|
161
|
-
return html
|
|
162
|
-
|
|
163
|
-
.
|
|
177
|
+
return html.replace(/<!--[\s\S]*?-->|<script\b[\s\S]*?<\/script>|<style\b[\s\S]*?<\/style>/gi, (m) => {
|
|
178
|
+
const blank = m.replace(/[^\r\n]/g, ' ');
|
|
179
|
+
return m.startsWith('<!--') ? `<${blank.slice(1, -1)}>` : blank;
|
|
180
|
+
});
|
|
164
181
|
}
|
|
165
182
|
|
|
166
183
|
function fromHtml({ source, rel }) {
|
|
@@ -193,7 +210,7 @@ function fromHtml({ source, rel }) {
|
|
|
193
210
|
|
|
194
211
|
// 3. <title> is the page's own name — always copy.
|
|
195
212
|
const titleRe = /<title>([^<]{2,200})<\/title>/gi;
|
|
196
|
-
while ((m = titleRe.exec(
|
|
213
|
+
while ((m = titleRe.exec(cleaned)) !== null) {
|
|
197
214
|
const titleStart = m.index + '<title>'.length;
|
|
198
215
|
out.push({ text: m[1].replace(/\s+/g, ' ').trim(), file: rel, line: lineAt(starts, m.index), origin: 'html-title', confidence: 'certain', ...trimmedSpan(m[1], titleStart) });
|
|
199
216
|
}
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.21.
|
|
78
|
+
const CORE_VERSION = '1.21.11'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
package/tests/copy_inventory.mjs
CHANGED
|
@@ -98,6 +98,68 @@ test('stripEmbedded keeps line numbers truthful', () => {
|
|
|
98
98
|
assert.equal(copy.line, 6, 'a stripped script must not shift the lines after it — a wrong line number sends an artist to the wrong place');
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
+
// Task 1004545. street.html's header comment held a literal `<a>`, which opened a
|
|
102
|
+
// fake text node; under CRLF that run was 403 characters, under LF 396 — so a
|
|
103
|
+
// Windows regen dropped a row CI kept and redded "the committed artifacts match".
|
|
104
|
+
// The fixture rebuilds both halves: a tag inside a comment, and a run sized to
|
|
105
|
+
// straddle the cap.
|
|
106
|
+
// Eight 45-char lines under a 28-char head: 396 chars on LF, 404 on CRLF.
|
|
107
|
+
const NEAR_CAP_LINES = Array.from({ length: 8 }, () => ` ${'word '.repeat(8)}s.`);
|
|
108
|
+
const EOL_FIXTURE = [
|
|
109
|
+
'<!doctype html>',
|
|
110
|
+
'<!-- Author note: a building is a door (an <a>) to its interior.',
|
|
111
|
+
' The template is street.css, the <style> on the tokens.',
|
|
112
|
+
'-->',
|
|
113
|
+
'<style>.x { color: red; }</style>',
|
|
114
|
+
'<p>A real sentence on the page,',
|
|
115
|
+
...NEAR_CAP_LINES.slice(0, -1),
|
|
116
|
+
`${NEAR_CAP_LINES.at(-1)}</p>`,
|
|
117
|
+
'<p title="A tooltip a person reads">Second real line.</p>',
|
|
118
|
+
].join('\n');
|
|
119
|
+
|
|
120
|
+
test('LF and CRLF checkouts extract identical rows (task 1004545)', () => {
|
|
121
|
+
const lf = inv.fromHtml({ source: EOL_FIXTURE, rel: 'p.html' });
|
|
122
|
+
const crlf = inv.fromHtml({ source: EOL_FIXTURE.replace(/\n/g, '\r\n'), rel: 'p.html' });
|
|
123
|
+
const strip = (rows) => rows.map(({ text, line, origin }) => ({ text, line, origin }));
|
|
124
|
+
assert.deepEqual(strip(crlf), strip(lf), 'the registry must not depend on the checkout\'s line endings');
|
|
125
|
+
const run = EOL_FIXTURE.slice(EOL_FIXTURE.indexOf('A real'), EOL_FIXTURE.indexOf('</p>'));
|
|
126
|
+
assert.ok(run.length <= 400 && run.replace(/\n/g, '\r\n').length > 400, 'the fixture must straddle the cap, or this test proves nothing');
|
|
127
|
+
// The multi-line sentence sits under the cap only when CRLF counts as one
|
|
128
|
+
// character — so this is the case that reds if the length rule regresses.
|
|
129
|
+
assert.ok(lf.some((r) => r.text.startsWith('A real sentence on the page')), 'a multi-line run under the cap is copy on LF');
|
|
130
|
+
assert.ok(crlf.some((r) => r.text.startsWith('A real sentence on the page')), 'and the same run is copy on CRLF');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('HTML comments are never copy, and a tag named inside one swallows nothing', () => {
|
|
134
|
+
const rows = inv.fromHtml({ source: EOL_FIXTURE, rel: 'p.html' });
|
|
135
|
+
const texts = rows.map((r) => r.text);
|
|
136
|
+
assert.ok(!texts.some((t) => /Author note|its interior|the tokens/.test(t)), 'comment text is an author note, not page copy');
|
|
137
|
+
// The comment names `<style>`: a strip pass that ran style-first would blank from
|
|
138
|
+
// there to the real </style> — harmless here, but the same shape with <script>
|
|
139
|
+
// ahead of real copy would erase it. Both real lines must survive.
|
|
140
|
+
assert.ok(texts.includes('Second real line.'));
|
|
141
|
+
assert.ok(texts.includes('A tooltip a person reads'));
|
|
142
|
+
const real = rows.find((r) => r.text === 'Second real line.');
|
|
143
|
+
assert.equal(real.line, 15, 'a stripped comment must not shift the lines after it');
|
|
144
|
+
// A span still addresses the file's own characters (copy-apply writes through it).
|
|
145
|
+
assert.equal(EOL_FIXTURE.slice(real.start, real.end), 'Second real line.');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('a marker comment still splits copy into the segments the server drops independently', () => {
|
|
149
|
+
// The landing footer: the first sentence is apex-only, the second is not. One
|
|
150
|
+
// fused row would give both a new id and hide that a child instance drops half.
|
|
151
|
+
const src = '<p><!--apex-only:start-->A non-profit, capture-resistant commons. <!--apex-only:end-->Built by agents, on the platform.</p>';
|
|
152
|
+
const texts = inv.fromHtml({ source: src, rel: 'p.html' }).map((r) => r.text);
|
|
153
|
+
assert.ok(texts.includes('A non-profit, capture-resistant commons.'));
|
|
154
|
+
assert.ok(texts.includes('Built by agents, on the platform.'));
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('a comment opener inside a script string does not eat the page after it', () => {
|
|
158
|
+
const src = '<script>const s = "<!--";</script>\n<p>Copy after the script.</p>\n<!-- x -->';
|
|
159
|
+
const texts = inv.fromHtml({ source: src, rel: 'p.html' }).map((r) => r.text);
|
|
160
|
+
assert.ok(texts.includes('Copy after the script.'));
|
|
161
|
+
});
|
|
162
|
+
|
|
101
163
|
test('the registry is deterministic and internally consistent', () => {
|
|
102
164
|
const a = inv.buildRegistry();
|
|
103
165
|
const b = inv.buildRegistry();
|
package/tests/hall_street.mjs
CHANGED
|
@@ -377,7 +377,7 @@ test('the page holds the prototype\'s header, the street, the readings and the c
|
|
|
377
377
|
for (const id of ['hudNeeds', 'hudMoving', 'hudShare', 'streetMode', 'streetSigns', 'streetPins', 'streetDoors', 'streetCard']) assert.match(html, new RegExp(`id="${id}"`), id);
|
|
378
378
|
assert.doesNotMatch(html, /app-sidebar|shell\.js/, 'no hall chrome, as the city');
|
|
379
379
|
const scripts = [...html.matchAll(/<script src="\/builders\/([a-z-]+)\.js/g)].map((m) => m[1]);
|
|
380
|
-
assert.deepEqual(scripts, ['city-draw', 'street-draw', 'street'], 'the shared kit loads first');
|
|
380
|
+
assert.deepEqual(scripts, ['city-draw', 'street-draw', 'street-inside', 'street'], 'the shared kit loads first, then the interiors (task 1004526)');
|
|
381
381
|
assert.equal(City.STREET_HREF, '/builders/street', 'the city\'s door is this page');
|
|
382
382
|
});
|
|
383
383
|
|