@bongos/core 1.20.48 → 1.20.50

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 (54) hide show
  1. package/.bongos-core.json +84 -54
  2. package/.claude/skills/new-project/SKILL.md +5 -0
  3. package/clients/bongos-client/index.d.ts +1 -1
  4. package/docs/api/openapi.json +3 -0
  5. package/docs/api-reference.md +1 -1
  6. package/docs/copy-inventory.md +434 -400
  7. package/docs/copy-registry.json +816 -508
  8. package/docs/module-api-changelog.md +4 -0
  9. package/docs/page-inventory.json +11 -2
  10. package/docs/page-readings.json +733 -690
  11. package/modules/hall-ui/public/criterion-uat-ui.js +280 -0
  12. package/modules/hall-ui/public/goal-map.html +5 -3
  13. package/modules/hall-ui/public/goals-page.js +23 -44
  14. package/modules/hall-ui/public/goals-render.js +24 -15
  15. package/modules/hall-ui/public/goals.css +45 -0
  16. package/modules/hall-ui/public/goals.html +5 -2
  17. package/modules/hall-ui/public/goals.states.json +38 -0
  18. package/modules/hall-ui/public/sky-data.js +9 -1
  19. package/modules/hall-ui/public/sky-interaction.js +1 -1
  20. package/modules/hall-ui/public/sky-panel.js +1 -1
  21. package/modules/hall-ui/public/thinking.html +5 -3
  22. package/modules/lifecycle/done-when.js +3 -1
  23. package/modules/lifecycle/sky.js +23 -8
  24. package/modules/platform-identity/routes/sso.js +5 -0
  25. package/modules/provisioning/migrations/provisioning_033_terms_ack.sql +33 -0
  26. package/modules/provisioning/onboard-plan.js +5 -0
  27. package/modules/provisioning/provisioning.js +7 -4
  28. package/modules/provisioning/routes/provisioning.js +3 -3
  29. package/modules/provisioning/terms-ack.js +36 -0
  30. package/modules/public-landing/public/projects.html +226 -77
  31. package/modules/public-landing/public/projects.probes.json +8 -2
  32. package/modules/public-landing/public/projects.states.json +16 -12
  33. package/modules/ui-design/kit/serve.js +6 -0
  34. package/package-lock.json +2 -2
  35. package/package.json +1 -1
  36. package/release-notes.json +12 -0
  37. package/scripts/hall-preview/server.js +2 -0
  38. package/src/module-api.js +1 -1
  39. package/tests/claim_action.mjs +6 -1
  40. package/tests/criterion_uat_ui.mjs +113 -0
  41. package/tests/goal_criterion_confirm_ui.mjs +188 -91
  42. package/tests/goal_map_page.mjs +2 -1
  43. package/tests/hall_sky.mjs +16 -0
  44. package/tests/helpers.mjs +3 -1
  45. package/tests/projects_hub.mjs +4 -2
  46. package/tests/projects_hub_app_status.mjs +1 -1
  47. package/tests/projects_hub_app_step.mjs +9 -9
  48. package/tests/projects_hub_module_picker.mjs +7 -7
  49. package/tests/projects_hub_pre_uat.mjs +4 -1
  50. package/tests/provisioning_terms_ack.mjs +216 -0
  51. package/tests/sky_read.mjs +7 -1
  52. package/tests/wizard_draft_resume.mjs +4 -4
  53. package/tests/wizard_front_door.mjs +271 -0
  54. package/tests/wizard_intent_resume.mjs +31 -19
@@ -107,6 +107,47 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
107
107
  pair steps aside for the checklist */
108
108
  .createSplit.wizDone{display:block;}
109
109
  .createSplit.wizDone .bongoCell{display:none;}
110
+ /* the front door (task 1004417, BV2.PS05): two screens before the numbered
111
+ steps. The rail is the steps', so it steps aside for both; the fork takes the
112
+ whole card like the done panel, the bongo pair giving way to the seed. */
113
+ #view-new .card.wizFront .steps{display:none;}
114
+ .createSplit.wizFork{display:block;}
115
+ .createSplit.wizFork .bongoCell{display:none;}
116
+ /* the one tick: a hairline row, the box in the accent, the whole row the target */
117
+ .termsAck{display:flex;gap:14px;align-items:flex-start;cursor:pointer;max-width:62ch;margin:6px 0 0;padding:16px 0 10px;border-top:1px solid var(--rule);}
118
+ .termsAck input{width:20px;height:20px;margin:2px 0 0;flex:none;accent-color:var(--accent);}
119
+ .termsAck span{font-size:16px;line-height:1.5;color:var(--ink);}
120
+ .termsRead{display:inline-block;margin-left:34px;padding:3px 0;min-height:24px;line-height:18px;font-size:14px;color:var(--ink);text-decoration:underline;text-underline-offset:3px;}
121
+ /* the door pill (DESIGN.md): two equal doors joined into one object — one grid
122
+ of two equal tracks inside one hairline pill; the demo door is transparent at
123
+ rest, the accent only on the one that goes on */
124
+ .doorPill{display:inline-grid;grid-template-columns:1fr 1fr;gap:6px;padding:7px;margin:6px 0 16px;border-radius:999px;border:1px solid var(--rule);background:color-mix(in srgb,var(--bg) 55%,transparent);}
125
+ #view-new .doorPill .btn.ghost{border-color:transparent;}
126
+ #view-new .doorPill .btn.ghost:hover{border-color:var(--rule);}
127
+ .demoSoon{font-size:14px;line-height:1.5;color:var(--ink-soft);max-width:52ch;margin:0 0 16px;}
128
+ /* the seed on the field plate: the world's own render, a hairline orbit and a
129
+ dashed one, the chrome blob cut out on top — nothing drawn but hairlines */
130
+ .forkBody{display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,380px);gap:48px;align-items:center;}
131
+ .forkStage{position:relative;aspect-ratio:1/1;border-radius:16px;overflow:hidden;background:var(--sky-bg) var(--field-plate) center/cover no-repeat;}
132
+ .forkOrbit{position:absolute;inset:20%;border:1px solid var(--rule);border-radius:50%;}
133
+ .forkOrbit.forkOrbitDash{inset:9%;border-style:dashed;border-color:var(--rule-soft);}
134
+ .forkSeed{position:absolute;left:50%;top:50%;width:44%;height:auto;transform:translate(-50%,-50%);}
135
+ /* the two routes on one hairline band */
136
+ .forkRoutes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 48px;margin-top:40px;}
137
+ .forkRoutes>div{border-top:1px solid var(--rule);padding-top:18px;}
138
+ .routeLbl{font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--ink-faint);margin:0;}
139
+ .routeT{font-family:var(--font-display);font-weight:300;font-size:26px;letter-spacing:-.02em;line-height:1.1;text-transform:lowercase;color:var(--ink);margin:8px 0 0;}
140
+ .routeD{font-size:14.5px;line-height:1.5;color:var(--ink-soft);margin:8px 0 0;max-width:52ch;}
141
+ @media (max-width:840px){
142
+ .forkBody,.forkRoutes{grid-template-columns:1fr;gap:28px;}
143
+ .forkStage{max-width:300px;}
144
+ .forkRoutes{margin-top:32px;}
145
+ }
146
+ /* under 520 the two doors cannot sit side by side at 48px, so they stack —
147
+ still two equal doors in one object */
148
+ @media (max-width:520px){
149
+ .doorPill{display:grid;grid-template-columns:1fr;width:100%;border-radius:32px;}
150
+ }
110
151
 
111
152
  /* a field: the label in the label face above, the input on one bottom
112
153
  hairline that takes ink on focus (the bar's search field), the hint under
@@ -1085,23 +1126,24 @@ summary{min-height:24px;padding:3px 0;}
1085
1126
 
1086
1127
  <!-- ══════════════════ VIEW · NEW PROJECT ══════════════════════════════════
1087
1128
  The whole create wizard, absorbed from /create (task 1002763; direction
1088
- §4 — that route now 302s here). Eight panels behind the six-beat rail; the
1129
+ §4 — that route now 302s here). The front door's two screens (terms, then
1130
+ demo or create — task 1004417), then eight panels behind the rail; the
1089
1131
  wizard block in the script below drives them. Same trust boundary as
1090
1132
  ever: every button here only ENQUEUES a provisioning request (ADR 0111).
1091
- The name panel carries a static `on` so a no-script visitor still reads
1133
+ The terms panel carries a static `on` so a no-script visitor still reads
1092
1134
  step 1 rather than an empty card. -->
1093
1135
  <section id="view-new" hidden>
1094
1136
  <div class="wrap viewWrap">
1095
- <div class="card">
1137
+ <div class="card wizFront">
1096
1138
  <ol class="steps" aria-label="Creation steps">
1097
- <li class="now" data-step="1" aria-current="step"><span class="snum">1</span><span class="slbl">Name</span></li>
1098
- <li data-step="2"><span class="snum">2</span><span class="slbl">Type</span></li>
1099
- <li data-step="3"><span class="snum">3</span><span class="slbl">About</span></li>
1100
- <li data-step="4"><span class="snum">4</span><span class="slbl">Modules</span></li>
1101
- <li data-step="5"><span class="snum">5</span><span class="slbl">Home</span></li>
1102
- <li data-step="6"><span class="snum">6</span><span class="slbl">Address</span></li>
1103
- <li data-step="7"><span class="snum">7</span><span class="slbl">App</span></li>
1104
- <li data-step="8"><span class="snum">8</span><span class="slbl">Create</span></li>
1139
+ <li class="now" data-step="3" aria-current="step"><span class="snum">1</span><span class="slbl">Name</span></li>
1140
+ <li data-step="4"><span class="snum">2</span><span class="slbl">Type</span></li>
1141
+ <li data-step="5"><span class="snum">3</span><span class="slbl">About</span></li>
1142
+ <li data-step="6"><span class="snum">4</span><span class="slbl">Modules</span></li>
1143
+ <li data-step="7"><span class="snum">5</span><span class="slbl">Home</span></li>
1144
+ <li data-step="8"><span class="snum">6</span><span class="slbl">Address</span></li>
1145
+ <li data-step="9"><span class="snum">7</span><span class="slbl">App</span></li>
1146
+ <li data-step="10"><span class="snum">8</span><span class="slbl">Create</span></li>
1105
1147
  </ol>
1106
1148
 
1107
1149
  <div class="createSplit">
@@ -1140,17 +1182,85 @@ summary{min-height:24px;padding:3px 0;}
1140
1182
  <div class="alert" id="wizGateAlert" role="alert"></div>
1141
1183
  </section>
1142
1184
 
1143
- <!-- step 1 · name (the hub's original step-1 form, now the wizard's) -->
1144
- <section class="panel on" id="panel-name" aria-labelledby="name-h">
1145
- <h1 id="name-h">Start a project</h1>
1146
- <p class="lede">Your own project: its own repository, its own home on the web, and a hall of AI builders
1147
- who do the building. You set the direction; agents lay down the code.</p>
1185
+ <!-- step 1 · the front door, part one: the terms (task 1004417, BV2.PS05; the
1186
+ canvas's Main.dc.html, docs/design/project-startup-direction.md). Before
1187
+ anything is asked, the founder acknowledges the terms. Sign-in stays where
1188
+ it was: the gate above comes first. The tick rides the create request as
1189
+ `terms_acknowledged` and the SERVER records which terms version it was
1190
+ (modules/provisioning/terms-ack.js), so this page never names one. The rail
1191
+ is for the numbered steps, so it steps aside on both front-door screens. -->
1192
+ <section class="panel on" id="panel-terms" aria-labelledby="terms-h">
1148
1193
  <!-- The standup already being watched, kept one click away (task 1003503).
1149
- A deliberate "New project" click opens THIS fresh step 1; the previous
1194
+ A deliberate "New project" click opens THIS fresh step 1 (the front door since task 1004417); the previous
1150
1195
  project's done panel is reachable here instead of taking the panel over.
1151
1196
  Baked markup, hidden until enter() has a record to name. -->
1152
1197
  <p class="resumeOffer" id="wizResume" hidden>still watching <strong id="wizResumeName">your project</strong> — <a href="#" id="wizResumeGo">resume it</a></p>
1153
- <form id="newForm" data-next="2">
1198
+ <h1 id="terms-h">Anything you want to make</h1>
1199
+ <p class="lede"><span data-brand-product-inline>Cloud Bongos</span> can be used for any project, by any kind of project entity: from a solo developer to a large corporation.</p>
1200
+ <p class="lede">Because of the sensitive nature of this platform and its projects, we highly recommend you review the legal terms as diligently as is appropriate for your project entity type.</p>
1201
+ <form data-next="2">
1202
+ <label class="termsAck">
1203
+ <input type="checkbox" id="termsAck" aria-describedby="h-terms">
1204
+ <span>I can sign legally, or can get a signature, for the use of this platform, and I acknowledge the terms and conditions.</span>
1205
+ </label>
1206
+ <a class="termsRead" href="/terms" target="_blank" rel="noopener">Read the terms</a>
1207
+ <div class="hint" id="h-terms">&nbsp;</div>
1208
+ <div class="nav">
1209
+ <span></span>
1210
+ <button type="submit" class="btn">Proceed to project creation</button>
1211
+ </div>
1212
+ </form>
1213
+ </section>
1214
+
1215
+ <!-- step 2 · the front door, part two: demo or create (task 1004417; the canvas's
1216
+ Fork.dc.html). Two equal ways in, so it is the world's door pill (DESIGN.md):
1217
+ two doors joined into one object, equal in size, the accent only on the one
1218
+ that goes on. The seed stands on the field plate beside it. The demo is its
1219
+ own task (BV2.PS09); until it ships, its door says so here instead of
1220
+ leading anywhere. -->
1221
+ <section class="panel" id="panel-fork" aria-labelledby="fork-h">
1222
+ <div class="forkBody">
1223
+ <div>
1224
+ <h1 id="fork-h">You are now creating a digital planet</h1>
1225
+ <p class="lede">If that sounds like too much for now, try our demo system. Otherwise, proceed with planet initiation :)</p>
1226
+ <form data-next="3">
1227
+ <div class="doorPill" role="group" aria-label="How to begin">
1228
+ <button type="button" class="btn big ghost" id="wizDemo" aria-controls="demoSoon" aria-expanded="false">Try the demo</button>
1229
+ <button type="submit" class="btn big">Begin planet creation</button>
1230
+ </div>
1231
+ <p class="demoSoon" id="demoSoon" hidden>The demo isn’t open yet. It’s being built now; until it opens, begin planet creation to make a real project.</p>
1232
+ <div class="nav">
1233
+ <button type="button" class="btn ghost" data-back="1">← Back</button>
1234
+ <span></span>
1235
+ </div>
1236
+ </form>
1237
+ </div>
1238
+ <div class="forkStage" aria-hidden="true">
1239
+ <span class="forkOrbit"></span>
1240
+ <span class="forkOrbit forkOrbitDash"></span>
1241
+ <img class="forkSeed" src="/assets/world/r2-chrome-blob-one-cut.webp" alt="">
1242
+ </div>
1243
+ </div>
1244
+ <div class="forkRoutes">
1245
+ <div>
1246
+ <p class="routeLbl">Route 1 · demo · coming soon</p>
1247
+ <p class="routeT">Training wheels</p>
1248
+ <p class="routeD">Pick how many people, how many hours each, and an idea. The platform checks that it fits, picks the settings, and you learn by building something small. Keep your planet at the end if you like it.</p>
1249
+ </div>
1250
+ <div>
1251
+ <p class="routeLbl">Route 2 · planet creation</p>
1252
+ <p class="routeT">Create your planet</p>
1253
+ <p class="routeD">Answer a few questions about your project, choose where its code and its app live, and it stands up as yours.</p>
1254
+ </div>
1255
+ </div>
1256
+ </section>
1257
+
1258
+ <!-- step 3 · name (the hub's original step-1 form, now the wizard's) -->
1259
+ <section class="panel" id="panel-name" aria-labelledby="name-h">
1260
+ <h1 id="name-h">Start a project</h1>
1261
+ <p class="lede">Your own project: its own repository, its own home on the web, and a hall of AI builders
1262
+ who do the building. You set the direction; agents lay down the code.</p>
1263
+ <form id="newForm" data-next="4">
1154
1264
  <label class="wizField"><span>Project name</span>
1155
1265
  <input type="text" id="newName" placeholder="What should it be called?" autocomplete="off" maxlength="80" aria-label="Project name">
1156
1266
  <div class="hint" id="h-name">&nbsp;</div>
@@ -1174,7 +1284,7 @@ summary{min-height:24px;padding:3px 0;}
1174
1284
  <section class="panel" id="panel-type" aria-labelledby="type-h">
1175
1285
  <h1 id="type-h">What kind of project is it?</h1>
1176
1286
  <p class="lede">Pick the shape that fits best — it’s how the project is listed on the map, and you can change it later from the project’s own page. Not sure is a fine answer.</p>
1177
- <form data-next="3">
1287
+ <form data-next="5">
1178
1288
  <div class="typeCards" id="typeCards" role="group" aria-label="Project type">
1179
1289
  <button type="button" class="tpill" data-type="game" aria-pressed="false">Game</button>
1180
1290
  <button type="button" class="tpill" data-type="research" aria-pressed="false">Research</button>
@@ -1188,7 +1298,7 @@ summary{min-height:24px;padding:3px 0;}
1188
1298
  </div>
1189
1299
  <div class="hint" id="h-projtype">&nbsp;</div>
1190
1300
  <div class="nav">
1191
- <button type="button" class="btn ghost" data-back="1">← Back</button>
1301
+ <button type="button" class="btn ghost" data-back="3">← Back</button>
1192
1302
  <button type="submit" class="btn">Next →</button>
1193
1303
  </div>
1194
1304
  </form>
@@ -1206,7 +1316,7 @@ summary{min-height:24px;padding:3px 0;}
1206
1316
  <section class="panel" id="panel-detail" aria-labelledby="detail-h">
1207
1317
  <h1 id="detail-h">Tell us about it</h1>
1208
1318
  <p class="lede">Optional — skip it and nothing about your project changes. Answering shapes what we set up for you, and a description is what puts the project on the public map.</p>
1209
- <form data-next="4">
1319
+ <form data-next="6">
1210
1320
  <label class="wizField"><span>What are you building? <small>(a sentence or two)</small></span>
1211
1321
  <textarea id="f-desc" rows="3" maxlength="600" placeholder="A co-op farming game where the seasons never repeat."></textarea>
1212
1322
  </label>
@@ -1219,7 +1329,7 @@ summary{min-height:24px;padding:3px 0;}
1219
1329
  </div>
1220
1330
  <div class="reassure" id="detailSkipNote"></div>
1221
1331
  <div class="nav">
1222
- <button type="button" class="btn ghost" data-back="2">← Back</button>
1332
+ <button type="button" class="btn ghost" data-back="4">← Back</button>
1223
1333
  <span class="navPair">
1224
1334
  <button type="button" class="btn ghost" id="skipDetail">Skip for now</button>
1225
1335
  <button type="submit" class="btn">Next →</button>
@@ -1242,7 +1352,7 @@ summary{min-height:24px;padding:3px 0;}
1242
1352
  <section class="panel" id="panel-modules" aria-labelledby="mod-h">
1243
1353
  <h1 id="mod-h">What it comes with</h1>
1244
1354
  <p class="lede">Optional — skip it and you get the suggested set below, shaped by what you just told us. These are extras on top of everything every project already has, and you can switch any of them on or off later.</p>
1245
- <form data-next="5">
1355
+ <form data-next="7">
1246
1356
  <div class="wizField"><span id="modLbl">Extras for this project</span>
1247
1357
  <!-- the catalog search (task 1002340, BV1.R21). The wizard's own
1248
1358
  search idiom (#ghSearch): a plain field on one hairline, no
@@ -1258,7 +1368,7 @@ summary{min-height:24px;padding:3px 0;}
1258
1368
  <div class="reassure" id="modCoreNote"></div>
1259
1369
  <div class="hint" id="h-modules">&nbsp;</div>
1260
1370
  <div class="nav">
1261
- <button type="button" class="btn ghost" data-back="3">← Back</button>
1371
+ <button type="button" class="btn ghost" data-back="5">← Back</button>
1262
1372
  <span class="navPair">
1263
1373
  <button type="button" class="btn ghost" id="skipModules">Skip for now</button>
1264
1374
  <button type="submit" class="btn">Next →</button>
@@ -1271,7 +1381,7 @@ summary{min-height:24px;padding:3px 0;}
1271
1381
  <section class="panel" id="panel-home" aria-labelledby="home-h">
1272
1382
  <h1 id="home-h">Where the code lives</h1>
1273
1383
  <p class="lede">Every project is a real GitHub repository that you own. Start from a clean slate, or bring a repo you already have.</p>
1274
- <form data-next="6">
1384
+ <form data-next="8">
1275
1385
  <div class="choices" role="group" aria-label="Starting point">
1276
1386
  <button type="button" class="choice" id="c-green" aria-pressed="true">
1277
1387
  <!-- token-built, not platform orange — public-landing/ ships wholesale to
@@ -1337,7 +1447,7 @@ summary{min-height:24px;padding:3px 0;}
1337
1447
  </div>
1338
1448
  <div class="hint" id="h-home">&nbsp;</div>
1339
1449
  <div class="nav">
1340
- <button type="button" class="btn ghost" data-back="4">← Back</button>
1450
+ <button type="button" class="btn ghost" data-back="6">← Back</button>
1341
1451
  <button type="submit" class="btn">Next →</button>
1342
1452
  </div>
1343
1453
  </form>
@@ -1355,7 +1465,7 @@ summary{min-height:24px;padding:3px 0;}
1355
1465
  <section class="panel" id="panel-address" aria-labelledby="addr-h">
1356
1466
  <h1 id="addr-h">Its address in the sky</h1>
1357
1467
  <p class="lede">The handle names your project on the platform — and its address comes with it. Once it stands up, a few GitHub steps (the next screen walks you through them) switch sign-in on.</p>
1358
- <form data-next="7">
1468
+ <form data-next="9">
1359
1469
  <label class="wizField"><span>Project handle</span>
1360
1470
  <input type="text" id="f-slug" placeholder="mercury" autocomplete="off" maxlength="40" spellcheck="false">
1361
1471
  <div class="hint" id="h-slug">&nbsp;</div>
@@ -1377,7 +1487,7 @@ summary{min-height:24px;padding:3px 0;}
1377
1487
  </label>
1378
1488
  </div>
1379
1489
  <div class="nav">
1380
- <button type="button" class="btn ghost" data-back="5">← Back</button>
1490
+ <button type="button" class="btn ghost" data-back="7">← Back</button>
1381
1491
  <button type="submit" class="btn">Next →</button>
1382
1492
  </div>
1383
1493
  </form>
@@ -1394,7 +1504,7 @@ summary{min-height:24px;padding:3px 0;}
1394
1504
  <h1 id="app-h">Where your app will run</h1>
1395
1505
  <p class="appHall"><b>We host your Builders' hall</b> — the place where the project gets built — at the address you just chose. There is nothing for you to set up.</p>
1396
1506
  <p class="lede">Your app is the thing the project builds. Choose where it should run, or decide later.</p>
1397
- <form data-next="8">
1507
+ <form data-next="10">
1398
1508
  <fieldset class="appOpts" id="appOpts">
1399
1509
  <legend>Where your app runs</legend>
1400
1510
  <label class="appOpt" id="appOptRender">
@@ -1452,7 +1562,7 @@ summary{min-height:24px;padding:3px 0;}
1452
1562
  <div class="hint" id="h-render" role="status">&nbsp;</div>
1453
1563
  </div>
1454
1564
  <div class="nav">
1455
- <button type="button" class="btn ghost" data-back="6">← Back</button>
1565
+ <button type="button" class="btn ghost" data-back="8">← Back</button>
1456
1566
  <button type="submit" class="btn">Next →</button>
1457
1567
  </div>
1458
1568
  </form>
@@ -1465,7 +1575,7 @@ summary{min-height:24px;padding:3px 0;}
1465
1575
  <ul class="review" id="reviewList"></ul>
1466
1576
  <div class="alert" id="createAlert" role="alert"></div>
1467
1577
  <div class="nav">
1468
- <button type="button" class="btn ghost" data-back="7">← Back</button>
1578
+ <button type="button" class="btn ghost" data-back="9">← Back</button>
1469
1579
  <button type="button" class="btn big" id="doCreate">Create my project</button>
1470
1580
  </div>
1471
1581
  <p class="finePrint">This files the request; the control plane does the real standup and nothing touches servers from this page. You'll get the few steps only you can do right after.</p>
@@ -3805,8 +3915,12 @@ summary{min-height:24px;padding:3px 0;}
3805
3915
  so a draft written under either older numbering must be ignored, not
3806
3916
  reinterpreted — a stale step 4 meant Address under v1 and Home under v3,
3807
3917
  and replaying it would land on the wrong panel with the rail already
3808
- marking the skipped ones done. Bump this key on EVERY renumbering. */
3809
- var DRAFT_KEY = 'cb-create-draft-v5';
3918
+ marking the skipped ones done. Bump this key on EVERY renumbering
3919
+ (-v6: the front door's two screens took steps 1 and 2, task 1004417). */
3920
+ /* `termsAck` is the front door's one tick (task 1004417). It is the founder's
3921
+ own answer, so it lives in the draft like every other one and survives the
3922
+ GitHub round-trip; the server, not this page, names the terms version. */
3923
+ var DRAFT_KEY = 'cb-create-draft-v6';
3810
3924
  var CREATED_KEY = 'cb-created-instance';
3811
3925
  /* `description` + `teamShape` are the optional About step (task 1002334) —
3812
3926
  both legitimately stay empty, and empty is what the create request omits. */
@@ -3815,7 +3929,7 @@ summary{min-height:24px;padding:3px 0;}
3815
3929
  request omits the field), [] = the owner switched them all off, [...] =
3816
3930
  what they picked. Never seed it with the preselect — that would store an
3817
3931
  answer nobody gave. */
3818
- var state = { step: 0, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later' };
3932
+ var state = { step: 0, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later', termsAck: false };
3819
3933
  try { Object.assign(state, JSON.parse(sessionStorage.getItem(DRAFT_KEY) || '{}')); } catch (e) {}
3820
3934
  var authKnown = false; /* flips true when the boot's /me settles, either way */
3821
3935
 
@@ -3829,7 +3943,7 @@ summary{min-height:24px;padding:3px 0;}
3829
3943
  state.name = handedName.trim().slice(0, 80);
3830
3944
  state.slug = deriveSlug(state.name); state.slugTouched = false;
3831
3945
  state.repo = deriveRepo(state.name); state.repoTouched = false;
3832
- state.step = state.step >= 1 && state.step <= 8 ? state.step : 1;
3946
+ state.step = state.step >= 1 && state.step <= 10 ? state.step : 1;
3833
3947
  try { sessionStorage.setItem(DRAFT_KEY, JSON.stringify(state)); } catch (e) {}
3834
3948
  }
3835
3949
  } catch (e) {}
@@ -4021,18 +4135,19 @@ summary{min-height:24px;padding:3px 0;}
4021
4135
  }
4022
4136
 
4023
4137
  /* ── step navigation ──
4024
- Nine steps since task 1004351: gate 0 · name 1 · type 2 · about 3 ·
4025
- modules 4 · home 5 · address 6 · app 7 · review 8 · done 9 (the rail shows
4026
- 1-8; done marks it all). About and Modules are the two steps Next can pass with
4027
- nothing filled in. */
4028
- var panels = { 0: 'panel-gate', 1: 'panel-name', 2: 'panel-type', 3: 'panel-detail', 4: 'panel-modules', 5: 'panel-home', 6: 'panel-address', 7: 'panel-app', 8: 'panel-review', 9: 'panel-done' };
4138
+ Since task 1004417 the front door comes first: gate 0 · terms 1 · fork 2 ·
4139
+ name 3 · type 4 · about 5 · modules 6 · home 7 · address 8 · app 9 · review 10 ·
4140
+ done 11. The rail numbers 3-10 as its 1-8 and steps aside on 1 and 2; done
4141
+ marks it all. About and Modules are the two steps Next can pass with nothing
4142
+ filled in. */
4143
+ var panels = { 0: 'panel-gate', 1: 'panel-terms', 2: 'panel-fork', 3: 'panel-name', 4: 'panel-type', 5: 'panel-detail', 6: 'panel-modules', 7: 'panel-home', 8: 'panel-address', 9: 'panel-app', 10: 'panel-review', 11: 'panel-done' };
4029
4144
  /* the rail at the done panel (task 1003244): "done" is the Create step
4030
4145
  still running — the marker stays on 5 until the project actually
4031
4146
  answers, and only then does the whole rail read finished. aria-current
4032
4147
  tells a screen reader the same thing. */
4033
4148
  function paintRail(step) {
4034
- var landed = step === 9 && !!(live && live.instStatus === 'active');
4035
- var cur = step === 9 ? 8 : step;
4149
+ var landed = step === 11 && !!(live && live.instStatus === 'active');
4150
+ var cur = step === 11 ? 10 : step;
4036
4151
  root.querySelectorAll('.steps li').forEach(function (li) {
4037
4152
  var n = Number(li.getAttribute('data-step'));
4038
4153
  var now = !landed && n === cur;
@@ -4043,7 +4158,7 @@ summary{min-height:24px;padding:3px 0;}
4043
4158
  the button role, the tab stop and the data-goto the delegated handler
4044
4159
  below reads. The done panel offers none — the project is filed, and
4045
4160
  there is nothing behind it to change. */
4046
- if (step < 9 && n < cur) {
4161
+ if (step < 11 && n < cur) {
4047
4162
  li.setAttribute('role', 'button');
4048
4163
  li.setAttribute('tabindex', '0');
4049
4164
  li.setAttribute('data-goto', String(n));
@@ -4062,7 +4177,11 @@ summary{min-height:24px;padding:3px 0;}
4062
4177
  paintRail(step);
4063
4178
  saveDraft();
4064
4179
  /* the done step takes the whole card — the bongo pair steps aside */
4065
- root.querySelector('.createSplit').classList.toggle('wizDone', step === 9);
4180
+ root.querySelector('.createSplit').classList.toggle('wizDone', step === 11);
4181
+ /* the front door (task 1004417): no rail on its two screens, and the fork
4182
+ takes the whole card for the seed on its plate */
4183
+ root.querySelector('.card').classList.toggle('wizFront', step === 1 || step === 2);
4184
+ root.querySelector('.createSplit').classList.toggle('wizFork', step === 2);
4066
4185
  /* focus moves ONLY on a deliberate step (the hub rule setView already
4067
4186
  applies to this view: never on boot, never on a background settle) */
4068
4187
  if (moveFocus) {
@@ -4074,17 +4193,17 @@ summary{min-height:24px;padding:3px 0;}
4074
4193
  draft's owner with myLogin()'s placeholder) */
4075
4194
  /* the picker repaints on entry, not once at boot: the owner can walk back
4076
4195
  to the Type step and change the answer the preselect is keyed to */
4077
- if (step === 4) renderModules();
4078
- if (step === 5) { syncHome(); if (authKnown) ensureRepoAccess(); }
4196
+ if (step === 6) renderModules();
4197
+ if (step === 7) { syncHome(); if (authKnown) ensureRepoAccess(); }
4079
4198
  /* a resumed draft can land PAST the Home step with the probe never run —
4080
4199
  Create would then file a repo it promised to make but never did */
4081
- else if (step > 5 && step < 9 && authKnown && repoAccess === null) ensureRepoAccess();
4200
+ else if (step > 7 && step < 11 && authKnown && repoAccess === null) ensureRepoAccess();
4082
4201
  /* re-check on every entry, not just on typing: a resumed draft arrives here with
4083
4202
  a handle nobody has asked the server about, and a handle free ten minutes ago
4084
4203
  may not be now (task 1002898 N10) */
4085
- if (step === 6) { checkSlugAvailable(); renderAddrPanel(); }
4086
- if (step === 7) { syncAppStep(); syncRenderSetup(); }
4087
- if (step === 8) renderReview();
4204
+ if (step === 8) { checkSlugAvailable(); renderAddrPanel(); }
4205
+ if (step === 9) { syncAppStep(); syncRenderSetup(); }
4206
+ if (step === 10) renderReview();
4088
4207
  }
4089
4208
 
4090
4209
  /* One delegated pair on the rail, so paintRail can add and drop data-goto
@@ -4105,6 +4224,20 @@ summary{min-height:24px;padding:3px 0;}
4105
4224
  });
4106
4225
  }
4107
4226
 
4227
+ /* ── the front door (task 1004417) ── the tick mirrors into the draft; the
4228
+ demo door opens a line saying the demo is not open yet (BV2.PS09 builds it) */
4229
+ $('termsAck').checked = !!state.termsAck;
4230
+ $('termsAck').addEventListener('change', function () {
4231
+ state.termsAck = !!this.checked;
4232
+ if (state.termsAck) { $('h-terms').textContent = '\u00a0'; $('h-terms').className = 'hint'; }
4233
+ saveDraft();
4234
+ });
4235
+ $('wizDemo').addEventListener('click', function () {
4236
+ var soon = $('demoSoon');
4237
+ soon.hidden = !soon.hidden;
4238
+ this.setAttribute('aria-expanded', soon.hidden ? 'false' : 'true');
4239
+ });
4240
+
4108
4241
  /* ── field wiring ── */
4109
4242
  $('newName').value = state.name;
4110
4243
  $('f-owner').value = state.owner;
@@ -4234,7 +4367,7 @@ summary{min-height:24px;padding:3px 0;}
4234
4367
  /* Skip = go on with whatever is (or isn't) filled in. It deliberately does
4235
4368
  NOT erase an answer already given: a visitor who typed a description and
4236
4369
  then pressed Skip meant "I'm done here", not "throw that away". */
4237
- $('skipDetail').addEventListener('click', function () { show(4, true); });
4370
+ $('skipDetail').addEventListener('click', function () { show(6, true); });
4238
4371
 
4239
4372
  /* ── the module picker (task 1002339, BV1.R20) ──
4240
4373
  ONE public read gives the panel both halves it needs: `optional` is the
@@ -4277,8 +4410,8 @@ summary{min-height:24px;padding:3px 0;}
4277
4410
  exact dishonesty the About row's "off the public map" clause exists to
4278
4411
  prevent, one screen before Create. */
4279
4412
  function repaintForBundles() {
4280
- if (state.step === 4) renderModules();
4281
- else if (state.step === 8) renderReview();
4413
+ if (state.step === 6) renderModules();
4414
+ else if (state.step === 10) renderReview();
4282
4415
  }
4283
4416
  /* The row for the declared type, or null before the read lands / for a type
4284
4417
  the table has no row for (including no type at all). */
@@ -4493,7 +4626,7 @@ summary{min-height:24px;padding:3px 0;}
4493
4626
  /* Skip = walk past without answering. It does NOT erase a toggle already
4494
4627
  made (the About step's rule), and with nothing said it leaves state.modules
4495
4628
  null so the server applies the bundle this panel was showing. */
4496
- $('skipModules').addEventListener('click', function () { show(5, true); });
4629
+ $('skipModules').addEventListener('click', function () { show(7, true); });
4497
4630
 
4498
4631
  /* ── GitHub-integrated repo picker (adopt) + auto-create (fresh) — task 1002099 / ADR 0143.
4499
4632
  Progressive enhancement: probe GET /github/repos once we reach the Home step.
@@ -4683,12 +4816,21 @@ summary{min-height:24px;padding:3px 0;}
4683
4816
 
4684
4817
  /* per-panel validation on Next */
4685
4818
  function validateStep(step) {
4686
- if (step === 7) return validateRender();
4819
+ if (step === 9) return validateRender();
4820
+ /* the front door's one tick (task 1004417): nothing past it until it is given */
4687
4821
  if (step === 1) {
4822
+ if (!state.termsAck) {
4823
+ $('h-terms').textContent = 'Tick the box to go on. It’s how your project records that you acknowledged the terms.';
4824
+ $('h-terms').className = 'hint err';
4825
+ return false;
4826
+ }
4827
+ return true;
4828
+ }
4829
+ if (step === 3) {
4688
4830
  if (!state.name.trim()) { $('h-name').textContent = 'Give it a name to start.'; $('h-name').className = 'hint err'; return false; }
4689
4831
  return true;
4690
4832
  }
4691
- if (step === 2) {
4833
+ if (step === 4) {
4692
4834
  if (!state.projType) {
4693
4835
  $('h-projtype').textContent = 'Pick one — Not Sure is a fine answer.';
4694
4836
  $('h-projtype').className = 'hint err';
@@ -4696,10 +4838,10 @@ summary{min-height:24px;padding:3px 0;}
4696
4838
  }
4697
4839
  return true;
4698
4840
  }
4699
- /* steps 3 (About) and 4 (Modules) have no clause: they are the optional
4841
+ /* steps 5 (About) and 6 (Modules) have no clause: they are the optional
4700
4842
  ones, and Next past an empty answer is the whole point (tasks 1002334,
4701
- 1002339). */
4702
- if (step === 5) {
4843
+ 1002339). Step 2 (the fork) has none either: its doors are the answer. */
4844
+ if (step === 7) {
4703
4845
  var homeErr = function (msg) { $('h-home').textContent = msg; $('h-home').className = 'hint err'; return false; };
4704
4846
  if (repoAccess === 'need-connect') return homeErr('Allow GitHub repo access to pick or create your repository — or choose “enter it manually”.');
4705
4847
  if (repoAccess === true && state.mode !== 'adopt') {
@@ -4714,7 +4856,7 @@ summary{min-height:24px;padding:3px 0;}
4714
4856
  $('h-home').innerHTML = '&nbsp;'; $('h-home').className = 'hint';
4715
4857
  return true;
4716
4858
  }
4717
- if (step === 6) {
4859
+ if (step === 8) {
4718
4860
  if (!validSlug(state.slug)) {
4719
4861
  $('h-slug').textContent = '2–40 lowercase letters, numbers, or dashes; no leading/trailing/double dash.';
4720
4862
  $('h-slug').className = 'hint err'; $('f-slug').classList.add('bad');
@@ -4833,7 +4975,7 @@ summary{min-height:24px;padding:3px 0;}
4833
4975
  : 'Once the project is up, we create your app on your Render account. Your key is used once, then thrown away.';
4834
4976
  /* then the app's own progress, from the same read the project's page uses (task 1004353) */
4835
4977
  var box = $('doneApp');
4836
- if (box) watchApp(instanceId, box, function () { return state.step === 9; }, 5000);
4978
+ if (box) watchApp(instanceId, box, function () { return state.step === 11; }, 5000);
4837
4979
  });
4838
4980
  }).catch(function (err) {
4839
4981
  note.className = 'hint err';
@@ -4949,6 +5091,11 @@ summary{min-height:24px;padding:3px 0;}
4949
5091
  var btn = this;
4950
5092
  var alertBox = $('createAlert');
4951
5093
  alertBox.classList.remove('on');
5094
+ /* a draft can reach Review without the front door's tick (one written before
5095
+ it existed is dropped by the key bump, but a cleared box is still a cleared
5096
+ box) — send the founder back to it rather than file an unacknowledged
5097
+ project (task 1004417) */
5098
+ if (!state.termsAck) { show(1, true); validateStep(1); return; }
4952
5099
  btn.disabled = true; btn.textContent = 'Raising it into the sky…';
4953
5100
  ensureFreshRepo().then(function () {
4954
5101
  return fetch(API + '/provisioning/instances', {
@@ -4966,6 +5113,8 @@ summary{min-height:24px;padding:3px 0;}
4966
5113
  the server then applies the SAME starter bundle the panel showed,
4967
5114
  so a skip and an accept land the same modules */
4968
5115
  modules: modulesForCreate(),
5116
+ /* the front door's tick (task 1004417) — the server stamps WHICH terms */
5117
+ terms_acknowledged: state.termsAck ? true : undefined,
4969
5118
  hosting_shape: 'cloud-host',
4970
5119
  /* ONLY a bring-your-own domain travels (task 1002898 N2). The server owns
4971
5120
  the assigned <slug>.<apex> default (task 1002704) and applies it to an
@@ -5010,7 +5159,7 @@ summary{min-height:24px;padding:3px 0;}
5010
5159
  sessionStorage.removeItem(DRAFT_KEY);
5011
5160
  } catch (e) {}
5012
5161
  renderDone();
5013
- show(9, true);
5162
+ show(11, true);
5014
5163
  sendRenderSetup(data.instance && data.instance.id); // the key rides the new project's own setup run (task 1004352)
5015
5164
  startProgress(data.instance && data.instance.id);
5016
5165
  }).catch(function (err) {
@@ -5019,7 +5168,7 @@ summary{min-height:24px;padding:3px 0;}
5019
5168
  if (err && err.gotoHome) {
5020
5169
  /* A repo-creation problem (name taken / reconnect) — bounce back to the Home
5021
5170
  step with the reason, so the user fixes it where the repo is chosen. */
5022
- show(5, true);
5171
+ show(7, true);
5023
5172
  $('h-home').textContent = err.homeMsg || 'Please revisit the repository step.';
5024
5173
  $('h-home').className = 'hint err';
5025
5174
  return;
@@ -5586,7 +5735,7 @@ summary{min-height:24px;padding:3px 0;}
5586
5735
  5s tick never clobbers an open dropdown or mid-flight button) */
5587
5736
  if (inst && inst.status !== live.instStatus) {
5588
5737
  live.instStatus = inst.status; renderSteps();
5589
- if (state.step === 9) paintRail(9); /* the rail finishes only when the project answers */
5738
+ if (state.step === 11) paintRail(11); /* the rail finishes only when the project answers */
5590
5739
  }
5591
5740
  var terminal = renderProgress(inst);
5592
5741
  if (!terminal) pollTimer = setTimeout(tick, 5000);
@@ -5626,7 +5775,7 @@ summary{min-height:24px;padding:3px 0;}
5626
5775
  is three-valued and null is its "nothing said" sentinel; leaving the key out
5627
5776
  left it UNDEFINED, which is not null — so pickedModules() reached .slice()
5628
5777
  on it and the second project's Modules step threw. */
5629
- state = { step: 1, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later' };
5778
+ state = { step: 1, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later', termsAck: false };
5630
5779
  $('newName').value = ''; $('f-owner').value = ''; $('f-repo').value = ''; $('f-slug').value = ''; $('f-domain').value = '';
5631
5780
  $('f-noaddr').checked = false; $('f-desc').value = '';
5632
5781
  /* Re-seed the owner from the signed-in account for the next project. */
@@ -5698,20 +5847,20 @@ summary{min-height:24px;padding:3px 0;}
5698
5847
  step is what says so. A landed create clears DRAFT_KEY — but show(9) then
5699
5848
  persists the done panel's own position straight back into it, so "is there a
5700
5849
  draft?" is always yes and would have skipped the reset forever, leaving the
5701
- finished project's name sitting in the fresh form. Only steps 1–8 are wizard
5850
+ finished project's name sitting in the fresh form. Only steps 1–10 are wizard
5702
5851
  steps: anything else is the done panel's bookkeeping, not a project someone
5703
5852
  is part-way through typing. */
5704
5853
  function enterCreated(created, focus) {
5705
5854
  if (focus && !resumeIntent) {
5706
5855
  var draft = null;
5707
5856
  try { draft = JSON.parse(sessionStorage.getItem(DRAFT_KEY) || 'null'); } catch (e) {}
5708
- var at = draft && draft.step >= 1 && draft.step <= 8 ? draft.step : 0;
5857
+ var at = draft && draft.step >= 1 && draft.step <= 10 ? draft.step : 0;
5709
5858
  if (!at) { resetForNewProject(); at = 1; }
5710
5859
  paintResumeOffer(created);
5711
- /* step 1's own focus target is the name field, not the heading — the same
5712
- deliberate-nav rule enter() applies below */
5860
+ /* step 1's own focus target is its one control, the terms tick, not the
5861
+ heading — the same deliberate-nav rule enter() applies below */
5713
5862
  show(at, at !== 1);
5714
- if (at === 1) $('newName').focus();
5863
+ if (at === 1) $('termsAck').focus();
5715
5864
  return;
5716
5865
  }
5717
5866
  resumeIntent = false;
@@ -5729,7 +5878,7 @@ summary{min-height:24px;padding:3px 0;}
5729
5878
  manifestState = created.manifest_state; manifestPending = true;
5730
5879
  }
5731
5880
  renderDone();
5732
- show(9, !!focus);
5881
+ show(11, !!focus);
5733
5882
  startProgress(created.id);
5734
5883
  resumePolls();
5735
5884
  }
@@ -5743,10 +5892,10 @@ summary{min-height:24px;padding:3px 0;}
5743
5892
  var created = authKnown ? createdRecord() : null;
5744
5893
  if (created && created.id) { enterCreated(created, !!focus); return; }
5745
5894
  paintResumeOffer(null);
5746
- /* before identity settles, never render past the name step: deeper steps
5747
- carry authenticated side effects (the Home-step repo probe), and onAuth()
5748
- re-enters to the real draft step the moment /me answers */
5749
- var step = authKnown && state.step >= 1 && state.step <= 8 ? state.step : 1;
5895
+ /* before identity settles, never render past step 1 (the terms, since task
5896
+ 1004417): deeper steps carry authenticated side effects (the Home-step repo
5897
+ probe), and onAuth() re-enters to the real draft step the moment /me answers */
5898
+ var step = authKnown && state.step >= 1 && state.step <= 10 ? state.step : 1;
5750
5899
  if (step === 1) {
5751
5900
  /* Pre-auth, step 1 is a PLACEHOLDER, not where the visitor is — but show()
5752
5901
  persists whatever step it renders, so it used to overwrite the draft's real
@@ -5755,8 +5904,8 @@ summary{min-height:24px;padding:3px 0;}
5755
5904
  step back after rendering the placeholder, in memory AND in the draft. */
5756
5905
  var resumeStep = state.step;
5757
5906
  show(1, false);
5758
- if (!authKnown && resumeStep >= 1 && resumeStep <= 8) { state.step = resumeStep; saveDraft(); }
5759
- if (focus) $('newName').focus();
5907
+ if (!authKnown && resumeStep >= 1 && resumeStep <= 10) { state.step = resumeStep; saveDraft(); }
5908
+ if (focus) $('termsAck').focus();
5760
5909
  } else {
5761
5910
  show(step, !!focus);
5762
5911
  }