@bongos/core 1.23.13 → 1.23.15

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 (56) hide show
  1. package/.bongos-core.json +90 -55
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +2 -0
  4. package/clients/bongos-client/index.cjs +2 -0
  5. package/clients/bongos-client/index.d.ts +2 -0
  6. package/clients/bongos-client/index.mjs +2 -0
  7. package/docs/api/openapi.json +22 -1
  8. package/docs/api-reference.md +3 -2
  9. package/docs/copy-inventory.md +1000 -946
  10. package/docs/copy-registry.json +2009 -1465
  11. package/docs/module-api-changelog.md +4 -2
  12. package/docs/page-inventory.json +10 -4
  13. package/docs/page-readings.json +593 -573
  14. package/modules/copy-desk/page-status.js +2 -2
  15. package/modules/copy-desk/tests/copy_page_status.mjs +1 -1
  16. package/modules/hall-ui/public/approval-queue-lib.js +1 -1
  17. package/modules/hall-ui/public/approval-queue.css +26 -12
  18. package/modules/hall-ui/public/approval-queue.js +40 -16
  19. package/modules/hall-ui/public/studio-lib.js +5 -3
  20. package/modules/hall-ui/public/studio.html +8 -8
  21. package/modules/hall-ui/public/studio.js +25 -5
  22. package/modules/hall-ui/public/studio.states.json +54 -4
  23. package/modules/hall-ui/public/welcome-boot.js +62 -12
  24. package/modules/platform-identity/builder-of-the-week.js +180 -0
  25. package/modules/platform-identity/migrations/platform_identity_032_weekly_features.sql +53 -0
  26. package/modules/platform-identity/routes/community-leaderboard.js +25 -1
  27. package/modules/public-landing/public/account.html +2 -1
  28. package/modules/public-landing/public/community-week-none.states.json +16 -0
  29. package/modules/public-landing/public/community.html +142 -13
  30. package/modules/public-landing/public/community.states.json +6 -4
  31. package/modules/public-landing/public/connections.html +2 -1
  32. package/modules/public-landing/public/contact.html +2 -1
  33. package/modules/public-landing/public/guild.html +2 -1
  34. package/modules/public-landing/public/index.html +2 -1
  35. package/modules/public-landing/public/invitations.html +2 -1
  36. package/modules/public-landing/public/privacy.html +2 -1
  37. package/modules/public-landing/public/projects.html +2 -1
  38. package/modules/public-landing/public/terms.html +2 -1
  39. package/modules/ui-design/kit/fixtures/community-week-none.json +6 -0
  40. package/modules/ui-design/kit/fixtures/community-week.json +11 -0
  41. package/modules/ui-design/kit/serve.js +8 -0
  42. package/package-lock.json +2 -2
  43. package/package.json +1 -1
  44. package/release-notes.json +15 -1
  45. package/scripts/bongos/run-unit-tests.js +4 -0
  46. package/src/module-api.js +1 -1
  47. package/src/platform-server.js +5 -5
  48. package/tests/builder_of_the_week.mjs +266 -0
  49. package/tests/builder_of_the_week_db.mjs +166 -0
  50. package/tests/hall_approval_queue.mjs +33 -9
  51. package/tests/hall_studio_home.mjs +74 -7
  52. package/tests/hub_account_page.mjs +2 -2
  53. package/tests/hub_community_page.mjs +136 -25
  54. package/tests/landing_legal_pages.mjs +2 -2
  55. package/tests/privacy_matrix.mjs +53 -8
  56. package/tests/welcome_boot_browser.mjs +45 -3
@@ -5,13 +5,15 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <!-- THE COMMUNITY PAGES (task 1003363; ADR 0217 D1, ADR 0337 D1/D3/D4.1, the community
7
7
  spec docs/specs/bongos-v1-community-tab.md D1/D3/D4/D8). Who is building, across every
8
- project, as three sub-pages of the bar's Community menu (owner, 2026-10-27), all served
9
- from this one file: /community is the leaderboard, /community/find the builder search,
10
- /community/recruiters the builders who hide their numbers but are open to recruiters.
8
+ project, as four sub-pages of the bar's Community menu (owner, 2026-10-27), all served
9
+ from this one file: /community is the leaderboard, /community/week the builder of the
10
+ week (task 1002981, spec D5), /community/find the builder search, /community/recruiters
11
+ the builders who hide their numbers but are open to recruiters.
11
12
  The script shows the section the path names and marks it current in the menu.
12
- VIEWING IS UNGATED (ADR 0217 D1): the leaderboard and the search are the same for every
13
- viewer, signed in or not. Both reads are public, viewer-independent routes
14
- (modules/platform-identity/routes/community-leaderboard.js, community-search.js),
13
+ VIEWING IS UNGATED (ADR 0217 D1): the leaderboard, the builder of the week and the search
14
+ are the same for every viewer, signed in or not. All three reads are public,
15
+ viewer-independent routes (modules/platform-identity/routes/community-leaderboard.js,
16
+ which also serves the builder of the week, and community-search.js),
15
17
  which decide WHO appears through account-visibility.js; these pages add no rule of
16
18
  their own. The one viewer-relative page is the recruiter list: drawn only from a 200 of
17
19
  GET /scouting, whose door (a project owner, or project.curate) is the server's, never
@@ -90,7 +92,28 @@
90
92
  .commDoor p{margin:0 0 18px;font-size:15px;line-height:1.55;color:var(--ink-soft);}
91
93
  .commDoor .gh{width:18px;height:18px;fill:currentColor;}
92
94
  .commDoor .btn{text-transform:none;}
95
+ /* Builder of the week (task 1002981): one line on the board, then its own page — the
96
+ crown, the rule, and the weeks before it as board rows with the week where the place is */
97
+ .commCrownLine{margin:-6px 0 10px;max-width:62ch;font-size:14.5px;line-height:1.5;color:var(--ink-soft);}
98
+ .commCrownLine a{display:inline-block;min-height:24px;padding:3px 0;line-height:18px;color:var(--ink);
99
+ text-decoration:underline;text-decoration-color:var(--accent);text-underline-offset:4px;}
100
+ .commCrownLine a:focus-visible{outline:2px solid var(--focus);outline-offset:3px;}
101
+ .commCrownLine strong{font-weight:500;color:var(--ink);}
102
+ .commCrown{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:14px 40px;
103
+ padding:0 0 26px;margin:0 0 6px;border-bottom:1px solid var(--rule-soft);}
104
+ .crownWhen{grid-column:1/-1;margin:0;font-family:var(--label-face);font-size:12.5px;color:var(--ink-faint);}
105
+ .crownWho{display:flex;align-items:center;gap:16px;min-width:0;}
106
+ .crownWho .connAv{width:64px;height:64px;}
107
+ .crownName{font-family:var(--font-display);font-weight:300;font-size:clamp(26px,3.4vw,34px);letter-spacing:-.02em;
108
+ line-height:1.1;color:var(--ink);overflow-wrap:anywhere;}
109
+ .crownNums{display:flex;gap:0 36px;text-align:right;}
110
+ .commSub{margin:24px 0 4px;font-family:var(--font-body);font-size:14.5px;font-weight:500;color:var(--ink);}
111
+ .weekRows .commRow{grid-template-columns:6.5rem 36px minmax(0,1fr) auto;}
112
+ .weekRows .commPlace{font-family:var(--label-face);}
93
113
  @media (max-width:480px){
114
+ .commCrown{grid-template-columns:minmax(0,1fr);}
115
+ .crownNums{text-align:left;}
116
+ .weekRows .commRow{grid-template-columns:7ch 32px minmax(0,1fr) auto;}
94
117
  .commRow,.commRows.canRecruit .commRow{grid-template-columns:3ch 32px minmax(0,1fr) auto;gap:0 10px;}
95
118
  .commRow .connAv{width:32px;height:32px;}
96
119
  .commNum{font-size:19px;}
@@ -132,6 +155,7 @@
132
155
  <div class="bandIn">
133
156
  <ul class="bandRow">
134
157
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
158
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
135
159
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
136
160
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
137
161
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -145,7 +169,7 @@
145
169
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
146
170
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
147
171
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
148
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
172
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
149
173
  </ul>
150
174
  </div>
151
175
  </div>
@@ -164,14 +188,15 @@
164
188
  <main class="acct" id="comm">
165
189
  <h1 class="vh">Community</h1>
166
190
 
167
- <!-- THREE SUB-PAGES, ONE FILE: every section is real markup; the script un-hides the one
168
- the path names (/community, /community/find, /community/recruiters). -->
191
+ <!-- FOUR SUB-PAGES, ONE FILE: every section is real markup; the script un-hides the one
192
+ the path names (/community, /community/week, /community/find, /community/recruiters). -->
169
193
  <div class="mineExtra">
170
194
  <!-- THE LEADERBOARD (spec D3): GET /community/leaderboard, one window and one craft
171
195
  at a time. The server ranks; this page draws its rows in the order and with the
172
196
  `place` it was given, and every count it prints is the length of a list. -->
173
197
  <section id="board" data-view="leaderboard" aria-labelledby="boardH">
174
198
  <h2 id="boardH">Leaderboard</h2>
199
+ <p class="commCrownLine" id="boardCrown" hidden></p>
175
200
  <div class="commFilters">
176
201
  <div class="commTabs" id="craftTabs" role="group" aria-label="Role">
177
202
  <button class="commTab" type="button" data-craft="" aria-pressed="true">Everyone</button>
@@ -199,6 +224,23 @@
199
224
  <p class="commNote" id="boardFine">A project reports a builder’s numbers when they sign in or ship there, so a window counts work when it was reported, not when it was done.</p>
200
225
  </section>
201
226
 
227
+ <!-- BUILDER OF THE WEEK (spec D5, task 1002981): GET /community/builder-of-the-week, the
228
+ last full week's winner and the weeks before it. The server decides the week and
229
+ records it (builder-of-the-week.js); this page draws what it was sent, the same for
230
+ every viewer, and states the rule in full (the spec: the formula is public). -->
231
+ <section id="week" data-view="week" aria-labelledby="weekH" hidden>
232
+ <h2 id="weekH">Builder of the week</h2>
233
+ <p class="commMsg" id="weekLoading" role="status">Reading the builder of the week…</p>
234
+ <p class="projMsg err" id="weekFailed" role="alert" hidden></p>
235
+ <div class="commCrown" id="weekCrown" hidden></div>
236
+ <p class="commMsg" id="weekNone" hidden></p>
237
+ <h3 class="commSub" id="weekRuleH">How it is chosen</h3>
238
+ <p class="commNote">The builder who earned the most {{currency}} across every project in one week, Monday to Sunday (UTC), among the builders who shipped at least one work that week. A tie goes to whoever shipped more works, then to whoever earned more karma. Builders who hide their numbers or keep their account private are not counted.</p>
239
+ <p class="commNote">Each week is decided once, the first time anyone opens this page after it ends, and it does not change after that. A project reports a builder’s numbers when they sign in or ship there, so a week counts work when it was reported, not when it was done.</p>
240
+ <h3 class="commSub" id="pastH" hidden>Past weeks</h3>
241
+ <ol class="commRows weekRows" id="weekPast" aria-labelledby="pastH"></ol>
242
+ </section>
243
+
202
244
  <!-- THE SEARCH (spec D4): GET /community/search, a name and an optional craft. A
203
245
  builder who hides their numbers is still found by name, and drops out once a
204
246
  craft is chosen — the server's rule (builder-search.js), never this page's. -->
@@ -262,10 +304,11 @@
262
304
  var QUERY_MIN = 2;
263
305
  var QUERY_MAX = 100;
264
306
  var CRAFT_WORD = { engineer: 'engineer', artist: 'artist', ideator: 'ideator', ui: 'designer' };
265
- // The three sub-pages this file is served as (platform-server.js's /community routes);
307
+ // The four sub-pages this file is served as (platform-server.js's /community routes);
266
308
  // the path picks one, and its menu items are marked current.
267
309
  var VIEWS = {
268
310
  leaderboard: { path: '/community', section: 'board', title: 'Leaderboard' },
311
+ week: { path: '/community/week', section: 'week', title: 'Builder of the week' },
269
312
  find: { path: '/community/find', section: 'find', title: 'Find a builder' },
270
313
  recruiters: { path: '/community/recruiters', section: 'recruit', title: 'Open to recruiters' },
271
314
  };
@@ -311,7 +354,7 @@
311
354
  return what + ' could not be read. Reload the page to try again.';
312
355
  }
313
356
  function viewOf(pathname) {
314
- var m = String(pathname || '').replace(/\/+$/, '').match(/^\/community(?:\/(find|recruiters))?$/);
357
+ var m = String(pathname || '').replace(/\/+$/, '').match(/^\/community(?:\/(week|find|recruiters))?$/);
315
358
  return m ? (m[1] || 'leaderboard') : 'leaderboard';
316
359
  }
317
360
 
@@ -442,6 +485,91 @@
442
485
  loadBoard();
443
486
  });
444
487
 
488
+ // ── the builder of the week (task 1002981, spec D5) ──────────────────────────
489
+ // The server decides each week and records it; this draws the answer as sent. On the
490
+ // board it is one line, and a failed or empty read draws nothing there.
491
+ var MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
492
+ // "19–25 Oct" for the Monday a week began on (UTC), the year added when asked
493
+ function weekSpan(start, withYear) {
494
+ var a = new Date(String(start) + 'T00:00:00Z');
495
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(String(start)) || !isFinite(a.getTime())) return '';
496
+ var b = new Date(a.getTime() + 6 * 24 * 60 * 60 * 1000);
497
+ var year = function (d) { return withYear ? ' ' + d.getUTCFullYear() : ''; };
498
+ if (a.getUTCMonth() === b.getUTCMonth()) return a.getUTCDate() + '–' + b.getUTCDate() + ' ' + MONTHS[b.getUTCMonth()] + year(b);
499
+ var first = a.getUTCDate() + ' ' + MONTHS[a.getUTCMonth()] + (a.getUTCFullYear() === b.getUTCFullYear() ? '' : year(a));
500
+ return first + ' – ' + b.getUTCDate() + ' ' + MONTHS[b.getUTCMonth()] + year(b);
501
+ }
502
+ function crownLine(r) {
503
+ var line = $('boardCrown');
504
+ var w = r.ok ? r.data.winner : null;
505
+ line.textContent = '';
506
+ line.hidden = !w;
507
+ if (!w) return;
508
+ var a = el('a', null, 'Builder of the week');
509
+ a.setAttribute('href', '/community/week');
510
+ line.appendChild(a);
511
+ line.appendChild(el('span', null, ': '));
512
+ line.appendChild(el('strong', null, w.display_name || w.handle || w.github_login || 'Builder'));
513
+ var span = weekSpan(r.data.week && r.data.week.start, false);
514
+ line.appendChild(el('span', null, ', ' + num(w.credits).toLocaleString() + ' ' + UNIT + (span ? ', ' + span : '')));
515
+ }
516
+ function stat(value, unit) {
517
+ var d = el('div');
518
+ d.appendChild(el('span', 'commNum', value));
519
+ d.appendChild(el('span', 'commUnit', unit));
520
+ return d;
521
+ }
522
+ function paintCrown(w, span) {
523
+ var box = $('weekCrown');
524
+ box.textContent = '';
525
+ if (span) box.appendChild(el('p', 'crownWhen', span));
526
+ var who = el('div', 'crownWho');
527
+ who.appendChild(face(w));
528
+ var main = el('div', 'mineRow__main');
529
+ main.appendChild(el('div', 'crownName', w.display_name || w.handle || w.github_login || 'Builder'));
530
+ if (w.handle) main.appendChild(el('span', 'mineRow__host', '@' + w.handle));
531
+ who.appendChild(main);
532
+ box.appendChild(who);
533
+ var nums = el('div', 'crownNums');
534
+ var ships = num(w.tasks_shipped);
535
+ nums.appendChild(stat(num(w.credits).toLocaleString(), UNIT));
536
+ nums.appendChild(stat(String(ships), ships === 1 ? 'work shipped' : 'works shipped'));
537
+ box.appendChild(nums);
538
+ box.hidden = false;
539
+ }
540
+ function pastRow(p) {
541
+ var li = el('li', 'commRow');
542
+ li.appendChild(el('span', 'commPlace', weekSpan(p.week_start, false)));
543
+ li.appendChild(face(p));
544
+ var main = nameBlock(p, p.handle ? '@' + p.handle : '');
545
+ main.appendChild(el('p', 'mineRow__hint', plural(num(p.tasks_shipped), 'work') + ' shipped'));
546
+ li.appendChild(main);
547
+ var credits = el('div', 'commCredits');
548
+ credits.appendChild(el('span', 'commNum', num(p.credits).toLocaleString()));
549
+ credits.appendChild(el('span', 'commUnit', UNIT));
550
+ li.appendChild(credits);
551
+ return li;
552
+ }
553
+ function loadWeek() {
554
+ return read('/community/builder-of-the-week').then(function (r) {
555
+ $('weekLoading').hidden = true;
556
+ if (!r.ok) {
557
+ $('weekFailed').textContent = failText(r.status, 'The builder of the week');
558
+ $('weekFailed').hidden = false;
559
+ return;
560
+ }
561
+ var span = weekSpan(r.data.week && r.data.week.start, true);
562
+ if (r.data.winner) paintCrown(r.data.winner, span);
563
+ else {
564
+ $('weekNone').textContent = span ? 'No builder of the week for ' + span + '.' : 'No builder of the week yet.';
565
+ $('weekNone').hidden = false;
566
+ }
567
+ var list = $('weekPast');
568
+ arr(r.data.past).forEach(function (p) { if (p) list.appendChild(pastRow(p)); });
569
+ $('pastH').hidden = !list.children.length;
570
+ });
571
+ }
572
+
445
573
  // ── the search ──────────────────────────────────────────────────────────────
446
574
  function say(text, kind) {
447
575
  var s = $('findStatus');
@@ -570,8 +698,9 @@
570
698
  });
571
699
  document.title = document.title + ' · ' + view.title;
572
700
  $('signinTop').setAttribute('href', '/api/bongos/auth/web/start?return=' + view.path + '&repos=1');
573
- if (VIEW === 'leaderboard') loadBoard();
574
- if (VIEW === 'recruiters') bar.ready.then(function (me) { if (me) loadRecruit(); else showRecruit('recruitDoor'); });
701
+ if (VIEW === 'leaderboard') { loadBoard(); read('/community/builder-of-the-week').then(crownLine); }
702
+ if (VIEW === 'week') loadWeek();
703
+ else if (VIEW === 'recruiters') bar.ready.then(function (me) { if (me) loadRecruit(); else showRecruit('recruitDoor'); });
575
704
  else bar.ready.then(function (me) { if (me) loadOwned(me, $(VIEW === 'find' ? 'findFor' : 'boardFor')); });
576
705
  })();
577
706
  </script>
@@ -1,5 +1,5 @@
1
1
  {
2
- "_": "The community pages' states for modules/ui-design/kit/render.js (task 1003363; ADR 0217 D1, ADR 0337 D4.1): one file served as three sub-pages of the bar's Community menu, each state naming its `url`. The leaderboard and the search are the same for every viewer, from the stub's fixtures (community-leaderboard.json: six builders all time, fewer in each window; community-search.json). The recruiter list signed out is a sign-in door, and signed in it is the default fixture's 403 (most builders own no project); community-recruiter.states.json is a project owner's list, community-empty.states.json a board with nobody on it. Dark only, like every apex page (ADR 0204).",
2
+ "_": "The community pages' states for modules/ui-design/kit/render.js (task 1003363; ADR 0217 D1, ADR 0337 D4.1): one file served as four sub-pages of the bar's Community menu, each state naming its `url`. The leaderboard, the builder of the week and the search are the same for every viewer, from the stub's fixtures (community-leaderboard.json: six builders all time, fewer in each window; community-week.json: a winner and four past weeks, task 1002981; community-search.json); community-week-none.states.json is a week nobody won. The recruiter list signed out is a sign-in door, and signed in it is the default fixture's 403 (most builders own no project); community-recruiter.states.json is a project owner's list, community-empty.states.json a board with nobody on it. Dark only, like every apex page (ADR 0204).",
3
3
  "page": "/community",
4
4
  "surface": "public-landing",
5
5
  "modes": ["dark"],
@@ -8,13 +8,15 @@
8
8
  "ignoreConsole": ["/api/(gds|bongos)/me", "/scouting", "\\b40[13]\\b", "Unauthorized", "Forbidden"],
9
9
  "ignoreControls": [".vh"],
10
10
  "states": {
11
- "out": { "auth": false, "actions": [["wait", 400]], "expect": { "visible": ["#board", "#boardList", "#boardWindow", "#signinTop", "#projTrig"], "hidden": ["#find", "#recruit", "#who", "#boardLoading", "#boardFailed", "#boardEmpty"], "count": [["#boardList .commRow", 6]], "value": [["#boardWindow", "all"]], "attr": [["#craftTabs [data-craft=\"\"]", "aria-pressed", "true"], ["#commTrig", "aria-current", "true"], ["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]], "text": [["#boardList .commRow:first-child .mineRow__name", "Priya Nair"], ["#boardList .commRow:first-child .commNum", "18,420"], ["#boardList .commRow:first-child .mineRow__hint", "212 works shipped · 64 karma"], ["#boardNote", "Credits earned across every project, since each builder started."]] } },
11
+ "out": { "auth": false, "actions": [["wait", 400]], "expect": { "visible": ["#board", "#boardList", "#boardWindow", "#signinTop", "#projTrig", "#boardCrown"], "hidden": ["#week", "#find", "#recruit", "#who", "#boardLoading", "#boardFailed", "#boardEmpty"], "href": [["#boardCrown a", "/community/week"]], "count": [["#boardList .commRow", 6]], "value": [["#boardWindow", "all"]], "attr": [["#craftTabs [data-craft=\"\"]", "aria-pressed", "true"], ["#commTrig", "aria-current", "true"], ["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]], "text": [["#boardList .commRow:first-child .mineRow__name", "Priya Nair"], ["#boardList .commRow:first-child .commNum", "18,420"], ["#boardList .commRow:first-child .mineRow__hint", "212 works shipped · 64 karma"], ["#boardNote", "Credits earned across every project, since each builder started."], ["#boardCrown", "Builder of the week: Ada Okafor, 1,240 credits, 19–25 Oct"]] } },
12
12
  "out-30d": { "auth": false, "actions": [["wait", 400], ["select", "#boardWindow", "30d"], ["wait", 300]], "expect": { "count": [["#boardList .commRow", 3]], "value": [["#boardWindow", "30d"]], "text": [["#boardList .commRow:first-child .mineRow__name", "Ada Okafor"], ["#boardNote", "Credits earned in the last 30 days, across every project."]] } },
13
13
  "out-artists": { "auth": false, "actions": [["wait", 400], ["click", "#craftTabs [data-craft=\"artist\"]"], ["wait", 300]], "expect": { "count": [["#boardList .commRow", 1]], "text": [["#boardList .commRow:first-child .mineRow__name", "Ada Okafor"], ["#boardList .commRow:first-child .commPlace", "1"]] } },
14
- "out-community-band": { "auth": false, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "hidden": ["#menuCommunity .knowCell"], "count": [["#menuCommunity .bandCell:not([hidden])", 3]], "attr": [["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]] } },
15
- "in-community-band": { "auth": true, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "count": [["#menuCommunity .bandCell:not([hidden])", 4]], "href": [["#menuCommunity .knowCell a", "/connections#connSuggest"]] } },
14
+ "out-community-band": { "auth": false, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "hidden": ["#menuCommunity .knowCell"], "count": [["#menuCommunity .bandCell:not([hidden])", 4]], "attr": [["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]] } },
15
+ "in-community-band": { "auth": true, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "count": [["#menuCommunity .bandCell:not([hidden])", 5]], "href": [["#menuCommunity .knowCell a", "/connections#connSuggest"]] } },
16
16
  "in-projects-band": { "auth": true, "actions": [["wait", 400], ["click", "#projTrig"], ["wait", 300]], "expect": { "visible": ["#menuProjects"], "count": [["#menuProjects .knowCell:not([hidden])", 1]] } },
17
17
  "out-projects-band": { "auth": false, "actions": [["wait", 400], ["click", "#projTrig"], ["wait", 300]], "expect": { "visible": ["#menuProjects"], "attr": [["#menuProjects a[href=\"/community\"]", "aria-current", "page"]] } },
18
+ "out-week": { "auth": false, "url": "/community/week", "actions": [["wait", 400]], "expect": { "visible": ["#week", "#weekCrown", "#pastH", "#weekPast"], "hidden": ["#board", "#find", "#recruit", "#weekLoading", "#weekFailed", "#weekNone"], "count": [["#weekPast .commRow", 4]], "attr": [["#menuCommunity a[href=\"/community/week\"]", "aria-current", "page"]], "text": [["#weekCrown .crownWhen", "19–25 Oct 2026"], ["#weekCrown .crownName", "Ada Okafor"], ["#weekCrown .crownNums div:first-child .commNum", "1,240"], ["#weekCrown .crownNums div:last-child .commUnit", "works shipped"], ["#weekPast .commRow:first-child .commPlace", "12–18 Oct"], ["#weekPast .commRow:nth-child(3) .commPlace", "28 Sep – 4 Oct"]] } },
19
+ "in-week": { "auth": true, "url": "/community/week", "actions": [["wait", 600]], "expect": { "visible": ["#week", "#weekCrown", "#who"], "hidden": ["#board", "#signinTop", "#weekFailed"], "count": [["#weekPast .commRow", 4]] } },
18
20
  "out-find": { "auth": false, "url": "/community/find", "actions": [["wait", 400]], "expect": { "visible": ["#find", "#findQ", "#findCraft", "#findBtn"], "hidden": ["#board", "#recruit"], "attr": [["#menuCommunity a[href=\"/community/find\"]", "aria-current", "page"]] } },
19
21
  "out-find-search": { "auth": false, "url": "/community/find", "actions": [["wait", 400], ["fill", "#findQ", "pri"], ["click", "#findBtn"], ["wait", 300]], "expect": { "count": [["#findList .mineRow", 2]], "text": [["#findStatus", "2 builders found."], ["#findList .mineRow:first-child .mineRow__hint", "engineer · designer"]] } },
20
22
  "out-recruiters": { "auth": false, "url": "/community/recruiters", "actions": [["wait", 400]], "expect": { "visible": ["#recruit", "#recruitDoor", "#recruitSignin"], "hidden": ["#board", "#find", "#recruitLoading", "#recruitClosed"], "count": [["#recruitList .mineRow", 0]], "attr": [["#menuCommunity a[href=\"/community/recruiters\"]", "aria-current", "page"]] } },
@@ -91,6 +91,7 @@
91
91
  <div class="bandIn">
92
92
  <ul class="bandRow">
93
93
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
94
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
94
95
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
95
96
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
96
97
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -104,7 +105,7 @@
104
105
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
105
106
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
106
107
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
107
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
108
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
108
109
  </ul>
109
110
  </div>
110
111
  </div>
@@ -71,6 +71,7 @@
71
71
  <div class="bandIn">
72
72
  <ul class="bandRow">
73
73
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
74
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
74
75
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
75
76
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
76
77
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -84,7 +85,7 @@
84
85
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
85
86
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
86
87
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
87
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
88
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
88
89
  </ul>
89
90
  </div>
90
91
  </div>
@@ -146,6 +146,7 @@
146
146
  <div class="bandIn">
147
147
  <ul class="bandRow">
148
148
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
149
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
149
150
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
150
151
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
151
152
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -159,7 +160,7 @@
159
160
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
160
161
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
161
162
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
162
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
163
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
163
164
  </ul>
164
165
  </div>
165
166
  </div>
@@ -720,6 +720,7 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
720
720
  <div class="bandIn">
721
721
  <ul class="bandRow">
722
722
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
723
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
723
724
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
724
725
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
725
726
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -733,7 +734,7 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
733
734
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">sky project directory</span></li>
734
735
  <li class="bandCell" id="mineCell" hidden><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
735
736
  <li class="bandCell"><a class="bandT" href="/projects?view=new">+ Create New Project</a><span class="bandC">fresh start/fresh idea</span></li>
736
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
737
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
737
738
  </ul>
738
739
  <!-- About and Docs are site pages, not project views: they live in the footer row with
739
740
  Privacy / Terms / Contact (owner, 2026-08-28; task 1003332). -->
@@ -101,6 +101,7 @@
101
101
  <div class="bandIn">
102
102
  <ul class="bandRow">
103
103
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
104
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
104
105
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
105
106
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
106
107
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -114,7 +115,7 @@
114
115
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
115
116
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
116
117
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
117
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
118
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
118
119
  </ul>
119
120
  </div>
120
121
  </div>
@@ -70,6 +70,7 @@
70
70
  <div class="bandIn">
71
71
  <ul class="bandRow">
72
72
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
73
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
73
74
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
74
75
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
75
76
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -83,7 +84,7 @@
83
84
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
84
85
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
85
86
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
86
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
87
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
87
88
  </ul>
88
89
  </div>
89
90
  </div>
@@ -859,6 +859,7 @@ summary{min-height:24px;padding:3px 0;}
859
859
  <div class="bandIn">
860
860
  <ul class="bandRow">
861
861
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
862
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
862
863
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
863
864
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
864
865
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -874,7 +875,7 @@ summary{min-height:24px;padding:3px 0;}
874
875
  <li class="bandCell"><a class="bandT" href="?view=map&amp;sub=table" data-nav="map" data-sub="table">Table</a><span class="bandC">the same projects as rows</span></li>
875
876
  <li class="bandCell"><a class="bandT" href="?view=mine" data-nav="mine">Your projects</a><span class="bandC">the ones you own</span></li>
876
877
  <li class="bandCell"><a class="bandT" href="?view=new" data-nav="new">New project</a><span class="bandC">five questions and a home</span></li>
877
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
878
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
878
879
  </ul>
879
880
  <!-- About and Docs are site pages, not project views: they live in the
880
881
  footer row with Privacy / Terms / Contact (owner, 2026-08-28; task 1003332). -->
@@ -70,6 +70,7 @@
70
70
  <div class="bandIn">
71
71
  <ul class="bandRow">
72
72
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
73
+ <li class="bandCell"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li>
73
74
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
74
75
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
75
76
  <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
@@ -83,7 +84,7 @@
83
84
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
84
85
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
85
86
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
86
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
87
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/week">Builder of the week</a><span class="bandC">the top earner of each week, and how it is chosen</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
87
88
  </ul>
88
89
  </div>
89
90
  </div>
@@ -0,0 +1,6 @@
1
+ {
2
+ "_": "GET /community/builder-of-the-week for the kit stub (task 1002981): a week nobody won (or whose winner hides) and no past weeks yet, the answer on a hub's first week.",
3
+ "week": { "start": "2026-10-19", "end": "2026-10-26" },
4
+ "winner": null,
5
+ "past": []
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "_": "GET /community/builder-of-the-week for the kit stub (task 1002981): the last full week, its winner and the weeks before it, newest first, as builder-of-the-week.js answers. A week whose winner hides, or that nobody won, is simply absent (21 Sep). Names are invented; the long one tests the row's wrap, 28 Sep the month-crossing label.",
3
+ "week": { "start": "2026-10-19", "end": "2026-10-26" },
4
+ "winner": { "week_start": "2026-10-19", "handle": "ada-okafor", "github_login": "adaokafor", "display_name": "Ada Okafor", "avatar_url": "/__kit/avatar.svg", "credits": 1240, "tasks_shipped": 4 },
5
+ "past": [
6
+ { "week_start": "2026-10-12", "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 2210, "tasks_shipped": 9 },
7
+ { "week_start": "2026-10-05", "handle": "maximiliana-van-der-berghe-lindqvist", "github_login": "mvdbl", "display_name": "Maximiliana van der Berghe-Lindqvist", "avatar_url": "/__kit/avatar.svg", "credits": 610, "tasks_shipped": 1 },
8
+ { "week_start": "2026-09-28", "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": 1875, "tasks_shipped": 6 },
9
+ { "week_start": "2026-09-14", "handle": "lin-wei", "github_login": "linwei", "display_name": "Lin Wei", "avatar_url": null, "credits": 430, "tasks_shipped": 2 }
10
+ ]
11
+ }
@@ -729,6 +729,13 @@ function communitySearch(res, u, origin) {
729
729
  .map((r) => withAvatar(r, origin));
730
730
  return json(res, 200, { query: q, discipline: disc || null, count: results.length, results, page: { limit: 20, offset: 0 } });
731
731
  }
732
+ // Builder of the Week (task 1002981): the fixture is already the route's answer — the
733
+ // week, its winner (or null) and the weeks before, newest first (builder-of-the-week.js).
734
+ function communityWeek(res, origin) {
735
+ const f = heldFixture('community-week');
736
+ if (stubStatus(res, f)) return;
737
+ return json(res, 200, { week: f.week, winner: f.winner ? withAvatar(f.winner, origin) : null, past: (f.past || []).map((r) => withAvatar(r, origin)) });
738
+ }
732
739
  function scoutingRead(res, origin) {
733
740
  const f = heldFixture('scouting');
734
741
  if (stubStatus(res, f)) return;
@@ -766,6 +773,7 @@ const server = http.createServer((req, res) => {
766
773
  if (rest === '/me/guild-requests' && req.method === 'GET') return AUTH ? myGuildRequests(res) : json(res, 401, UNAUTH);
767
774
  if (rest === '/community/leaderboard' && req.method === 'GET') return communityBoard(res, u, origin);
768
775
  if (rest === '/community/search' && req.method === 'GET') return communitySearch(res, u, origin);
776
+ if (rest === '/community/builder-of-the-week' && req.method === 'GET') return communityWeek(res, origin);
769
777
  if (rest === '/scouting' && req.method === 'GET') return AUTH ? scoutingRead(res, origin) : json(res, 401, UNAUTH);
770
778
  if (rest === '/connections' && req.method === 'GET') return AUTH ? connRead(res, 'list', origin) : json(res, 401, UNAUTH);
771
779
  if (rest === '/connections/requests' && req.method === 'GET') return AUTH ? connRead(res, 'requests', origin) : json(res, 401, UNAUTH);
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.23.13",
3
+ "version": "1.23.15",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.23.13",
9
+ "version": "1.23.15",
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.23.13",
3
+ "version": "1.23.15",
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",
@@ -10460,10 +10460,24 @@
10460
10460
  "text": "Project owners can now press Recruit next to any builder on the community leaderboard or search, which opens their project's invite page with that builder's name already filled in."
10461
10461
  }
10462
10462
  ],
10463
- "1.23.13": [
10463
+ "1.23.14": [
10464
+ {
10465
+ "id": "1004839",
10466
+ "text": "The studio is simpler for artists. Its four doors now read in plain words: Resume, Work through tweaks, Approve and confirm tweaks, and Needs to be reviewed. The approve door only shows for artists at metic or above, and an em"
10467
+ },
10468
+ {
10469
+ "id": "1004851",
10470
+ "text": "The Welcome page now greets people every time they sign in, not only on their first visit of the day. Visitors who are not signed in now land on the Welcome with a Sign in with GitHub button."
10471
+ },
10464
10472
  {
10465
10473
  "id": "1004644",
10466
10474
  "text": "The tweak editor's split view now shows the landing and status pages under the words, instead of opening a second window."
10467
10475
  }
10476
+ ],
10477
+ "1.23.15": [
10478
+ {
10479
+ "id": "1002981",
10480
+ "text": "The community pages now have a Builder of the week: each Monday the builder who earned the most in the week before, among those who shipped something, is crowned and kept on record. It has its own page, with the rule spelled o"
10481
+ }
10468
10482
  ]
10469
10483
  }
@@ -71,6 +71,10 @@ const INTEGRATION = new Set([
71
71
  // counting as zero, and the privacy matrix filtering are all planner facts the
72
72
  // DB-free route test can only assert the shape of.
73
73
  'community_leaderboard_db',
74
+ // task 1002981: Builder of the Week against real SQL — which snapshots open and
75
+ // close the week, the shipped-work floor and tie order, and the ON CONFLICT pin
76
+ // under two racing writers. The DB-free sibling is builder_of_the_week.
77
+ 'builder_of_the_week_db',
74
78
  // bfg, bfg_write, memory_isolation, memory_pull and setup_smoke LEFT this set under task
75
79
  // 1004865: none of them ever needed a database. Each failed on a stale test harness (a fake
76
80
  // server without res.fail, a stub on the wrong module, an old error shape, a renamed session
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.23.13'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.23.15'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');