@bongos/core 1.17.2 → 1.17.3

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 (77) hide show
  1. package/.bongos-core.json +292 -32
  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 +4 -2
  6. package/clients/bongos-client/index.mjs +2 -0
  7. package/docs/api/openapi.json +65 -26
  8. package/docs/api-reference.md +3 -2
  9. package/modules/hall-ui/public/builders.js +96 -646
  10. package/modules/hall-ui/public/goal-inbox.js +67 -26
  11. package/modules/hall-ui/public/goals-page.js +4 -1
  12. package/modules/hall-ui/public/goals.html +8 -0
  13. package/modules/hall-ui/public/hall-kit.js +474 -0
  14. package/modules/hall-ui/public/hall-widgets.js +11 -15
  15. package/modules/hall-ui/public/instances-panel.js +24 -3
  16. package/modules/hall-ui/public/new-project-wizard.js +6 -5
  17. package/modules/hall-ui/public/style.css +125 -0
  18. package/modules/hall-ui/public/work.css +194 -0
  19. package/modules/hall-ui/public/work.html +46 -374
  20. package/modules/hall-ui/public/work.js +137 -102
  21. package/modules/lifecycle/criterion-suggest.js +80 -0
  22. package/modules/lifecycle/db.js +42 -5
  23. package/modules/lifecycle/routes/goals.js +26 -0
  24. package/modules/lifecycle/routes/tasks.js +21 -0
  25. package/package-lock.json +2 -2
  26. package/package.json +1 -1
  27. package/scripts/hall-preview/README.md +103 -0
  28. package/scripts/hall-preview/fixtures/access-requests.json +1 -0
  29. package/scripts/hall-preview/fixtures/achievements.json +76 -0
  30. package/scripts/hall-preview/fixtures/analytics__builder.json +251 -0
  31. package/scripts/hall-preview/fixtures/audit-log.json +1 -0
  32. package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +1 -0
  33. package/scripts/hall-preview/fixtures/builders__active-claims.json +1 -0
  34. package/scripts/hall-preview/fixtures/builders__directory.json +81 -0
  35. package/scripts/hall-preview/fixtures/builders__roster.json +1 -0
  36. package/scripts/hall-preview/fixtures/goals.json +502 -0
  37. package/scripts/hall-preview/fixtures/goals__25.json +96 -0
  38. package/scripts/hall-preview/fixtures/goals__26.json +67 -0
  39. package/scripts/hall-preview/fixtures/goals__3.json +103 -0
  40. package/scripts/hall-preview/fixtures/goals__35.json +49 -0
  41. package/scripts/hall-preview/fixtures/goals__conflicts.json +154 -0
  42. package/scripts/hall-preview/fixtures/goals__detail.json +96 -0
  43. package/scripts/hall-preview/fixtures/goals__inbox.json +5 -0
  44. package/scripts/hall-preview/fixtures/goals__requests.json +3 -0
  45. package/scripts/hall-preview/fixtures/grades__by-builder.json +1 -0
  46. package/scripts/hall-preview/fixtures/inbox.json +330 -0
  47. package/scripts/hall-preview/fixtures/instance.json +124 -0
  48. package/scripts/hall-preview/fixtures/leaderboard.json +184 -0
  49. package/scripts/hall-preview/fixtures/me.json +476 -0
  50. package/scripts/hall-preview/fixtures/me__recent-ships.json +304 -0
  51. package/scripts/hall-preview/fixtures/override-requests.json +1 -0
  52. package/scripts/hall-preview/fixtures/provisioning__fleet.json +1 -0
  53. package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +1 -0
  54. package/scripts/hall-preview/fixtures/provisioning__instances.json +1 -0
  55. package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +516 -0
  56. package/scripts/hall-preview/fixtures/public__bounty-table.json +37 -0
  57. package/scripts/hall-preview/fixtures/public__cost-summary.json +742 -0
  58. package/scripts/hall-preview/fixtures/public__estimation-drift.json +41 -0
  59. package/scripts/hall-preview/fixtures/public__grades.json +50 -0
  60. package/scripts/hall-preview/fixtures/public__progress.json +124 -0
  61. package/scripts/hall-preview/fixtures/public__recent-shipped.json +426 -0
  62. package/scripts/hall-preview/fixtures/public__repo-health.json +160 -0
  63. package/scripts/hall-preview/fixtures/public__repo-info.json +5 -0
  64. package/scripts/hall-preview/fixtures/security__docs.json +1 -0
  65. package/scripts/hall-preview/fixtures/security__reports.json +1 -0
  66. package/scripts/hall-preview/fixtures/sessions__search.json +1 -0
  67. package/scripts/hall-preview/fixtures/tasks.json +2420 -0
  68. package/scripts/hall-preview/fixtures/tasks__claimable.json +2555 -0
  69. package/scripts/hall-preview/fixtures/tasks__detail.json +111 -0
  70. package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +330 -0
  71. package/scripts/hall-preview/fixtures/versions.json +89 -0
  72. package/scripts/hall-preview/refresh-fixtures.js +77 -0
  73. package/scripts/hall-preview/server.js +178 -0
  74. package/scripts/migrate.sh +29 -4
  75. package/src/bongos/optimizer.js +37 -2
  76. package/tests/criterion_suggest.mjs +106 -0
  77. package/tests/migrate_root_resolution.mjs +97 -0
@@ -10,218 +10,10 @@
10
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
11
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
12
12
  <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
13
- <style>
14
- /* Page-local styles for the Work Board — the pieces the shared kit doesn't
15
- carry (in-flight actions, claimable task cards, history list). Version
16
- progress bars + goals moved to the Roadmap page (task 1757). Everything
17
- derives from the shared design tokens so instance packs reskin this
18
- page along with the rest of the hall. */
19
-
20
- .kbd {
21
- display: inline-block;
22
- padding: 0 6px;
23
- border: 1px solid var(--border-strong);
24
- border-radius: 5px;
25
- background: var(--surface-2);
26
- font-size: 0.85em;
27
- font-weight: 600;
28
- color: var(--ink-soft);
29
- }
30
-
31
- .wip-builder { color: var(--ink); font-weight: 600; }
32
- .wip-builder small { color: var(--ink-soft); font-weight: 400; }
33
-
34
- /* ---- #616: claim/release actions on the work board ---- */
35
-
36
- /* Per-task action stack (Claim + Copy prompt). Sits in the task card's last
37
- grid cell. */
38
- .task__actions {
39
- display: flex;
40
- flex-direction: column;
41
- align-items: stretch;
42
- gap: 6px;
43
- }
44
- /* Claim is the primary action — filled accent so it reads above Copy. */
45
- .task__claim {
46
- background: var(--accent);
47
- border: 1px solid var(--accent-deep);
48
- color: #fff;
49
- border-radius: var(--radius-sm);
50
- font-size: 12.5px;
51
- font-weight: 600;
52
- padding: 5px 14px;
53
- cursor: pointer;
54
- white-space: nowrap;
55
- transition: background 150ms, opacity 150ms;
56
- }
57
- .task__claim:hover { background: var(--accent-deep); }
58
- .task__claim:disabled { opacity: 0.55; cursor: default; }
59
-
60
- /* Files a claimable task is responsible for (touches[]). */
61
- .task__touches {
62
- margin: 6px 0 0;
63
- font-size: 12px;
64
- color: var(--ink-faint);
65
- word-break: break-word;
66
- }
67
-
68
- .task__tag--newcomer {
69
- background: var(--ok-weak);
70
- color: var(--ok);
71
- border-color: color-mix(in srgb, var(--ok) 30%, transparent);
72
- }
73
- .task__tag--mine {
74
- background: var(--accent-weak);
75
- color: var(--accent-text);
76
- border-color: color-mix(in srgb, var(--accent) 35%, transparent);
77
- }
78
- /* task 1498 / ADR 0084: per-task rank floor. Outlined + emphasized (not a
79
- filled tag) so a gated task reads as "authority required", distinct from
80
- the filled newcomer tag. */
81
- .task__tag--rank {
82
- background: transparent;
83
- color: var(--warn);
84
- border-color: color-mix(in srgb, var(--warn) 45%, transparent);
85
- font-weight: 600;
86
- letter-spacing: 0.02em;
87
- }
88
- /* task 1752: the open (no floor) state — muted/neutral so "Any rank" reads as
89
- "open to all", not as a warning like the gated --rank tag above. */
90
- .task__tag--rank-open {
91
- background: transparent;
92
- color: var(--ink-faint);
93
- border-color: var(--border);
94
- }
95
- /* task 1753: the whole card is clickable → opens the shared task-detail overlay. */
96
- .task { cursor: pointer; }
97
- /* task 1754: collapsed Backlog group. */
98
- .backlog-summary { cursor: pointer; display: flex; align-items: baseline; gap: 8px; }
99
- .backlog-summary .scroll__h { display: inline; margin: 0; }
100
- .backlog-count { font-size: 13px; color: var(--ink-faint); }
101
- #backlog-list .history__row { cursor: pointer; }
102
-
103
- /* In-flight table: release action on the viewer's own claims. */
104
- .wip__action { text-align: right; white-space: nowrap; }
105
- .wip__release {
106
- background: var(--surface);
107
- border: 1px solid var(--border-strong);
108
- color: var(--ink-soft);
109
- border-radius: var(--radius-sm);
110
- font-size: 12px;
111
- font-weight: 600;
112
- padding: 4px 11px;
113
- cursor: pointer;
114
- transition: background 150ms, color 150ms, border-color 150ms;
115
- }
116
- .wip__release:hover:not(:disabled) {
117
- background: var(--danger-weak);
118
- color: var(--danger);
119
- border-color: color-mix(in srgb, var(--danger) 40%, transparent);
120
- }
121
- .wip__release:disabled { opacity: 0.55; cursor: default; }
122
- .wip__mine-none { color: var(--ink-faint); }
123
- .wip__row--mine { background: var(--accent-weak); }
124
-
125
- /* Recently-shipped history. */
126
- .history { display: flex; flex-direction: column; gap: 2px; margin-top: 6px; }
127
- .history__row {
128
- display: flex; align-items: baseline; gap: 12px;
129
- padding: 6px 4px;
130
- border-bottom: 1px solid var(--rule-soft);
131
- }
132
- .history__row:last-child { border-bottom: none; }
133
- .history__id {
134
- font-weight: 600; color: var(--ink-soft);
135
- font-variant-numeric: tabular-nums; min-width: 3.2em;
136
- }
137
- .history__title { flex: 1 1 auto; color: var(--ink); min-width: 0; }
138
- .history__when { color: var(--ink-faint); font-size: 12.5px; white-space: nowrap; }
139
-
140
- @media (max-width: 640px) {
141
- .task__actions { grid-column: 2; justify-self: start; flex-direction: row; }
142
- }
143
-
144
- /* ---- task 1759: multi-select + the bottom bulk-action toolbar ---- */
145
-
146
- .wip__select-cell { width: 1%; text-align: center; }
147
- .wip__select { width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent); }
148
-
149
- .bulk-toolbar {
150
- position: fixed;
151
- left: 50%;
152
- bottom: 20px;
153
- transform: translateX(-50%);
154
- z-index: 120;
155
- display: flex;
156
- align-items: center;
157
- gap: 14px;
158
- flex-wrap: wrap;
159
- background: var(--ink);
160
- color: var(--bg-card);
161
- padding: 10px 16px;
162
- border-radius: var(--radius);
163
- box-shadow: var(--shadow-pop);
164
- max-width: min(92vw, 720px);
165
- }
166
- .bulk-toolbar[hidden] { display: none; }
167
- .bulk-toolbar__count { font-size: 13px; font-weight: 600; white-space: nowrap; }
168
- .bulk-toolbar__actions { display: flex; gap: 8px; flex-wrap: wrap; }
169
- .bulk-toolbar__btn {
170
- background: rgba(255, 255, 255, 0.12);
171
- border: 1px solid rgba(255, 255, 255, 0.25);
172
- color: var(--bg-card);
173
- border-radius: var(--radius-sm);
174
- font-size: 12.5px;
175
- font-weight: 600;
176
- padding: 6px 12px;
177
- cursor: pointer;
178
- white-space: nowrap;
179
- transition: background 150ms, opacity 150ms;
180
- }
181
- .bulk-toolbar__btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.22); }
182
- .bulk-toolbar__btn:disabled { opacity: 0.4; cursor: not-allowed; }
183
- .bulk-toolbar__clear {
184
- background: transparent;
185
- border: none;
186
- color: var(--bg-card);
187
- opacity: 0.75;
188
- font-size: 12.5px;
189
- cursor: pointer;
190
- padding: 4px 6px;
191
- }
192
- .bulk-toolbar__clear:hover { opacity: 1; }
193
-
194
- @media (max-width: 640px) {
195
- .bulk-toolbar { left: 12px; right: 12px; bottom: 12px; transform: none; max-width: none; }
196
- }
197
-
198
- /* ---- task 1899: capped lists (the goals-page pattern, task 1888) ---- */
199
- /* Small header count pill; .pager / .pager__range / .btn-ghost live in the
200
- shared style.css and are reused as-is. */
201
- .count-pill {
202
- display: inline-flex; align-items: center; justify-content: center;
203
- min-width: 20px; height: 18px; padding: 0 6px; margin-left: 8px;
204
- border-radius: 999px; background: var(--surface-2); color: var(--ink-soft);
205
- font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
206
- vertical-align: 2px;
207
- }
208
-
209
- /* ---- task 1931: paginated Ready list (Per-page dropdown + Prev/Next) ---- */
210
- /* .pager / .pager__range / .btn-ghost come from the shared style.css; these
211
- extend that pager into a two-sided bar (range left, controls right). */
212
- .pager--paged { justify-content: space-between; flex-wrap: wrap; gap: 10px 16px; }
213
- .pager__nav { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
214
- .pager__perpage {
215
- display: inline-flex; align-items: center; gap: 6px;
216
- font-size: 12px; color: var(--ink-faint);
217
- }
218
- .pager__perpage select { height: 30px; padding: 2px 8px; font-size: 13px; }
219
- .pager__page {
220
- font-size: 12.5px; color: var(--ink-soft);
221
- font-variant-numeric: tabular-nums; min-width: 6.5em; text-align: center;
222
- }
223
- .pager__nav .pager__btn:disabled { opacity: 0.4; cursor: default; }
224
- </style>
13
+ <!-- Page-local styles (task 2170) — extracted from the old inline <style>
14
+ block per the hall placement rules; shared pager/count-pill styles now
15
+ live in style.css's hall-kit section. -->
16
+ <link rel="stylesheet" href="/builders/work.css">
225
17
  </head>
226
18
  <body data-page="work" data-page-title="Work">
227
19
 
@@ -249,10 +41,34 @@
249
41
  </p>
250
42
  </section>
251
43
 
252
- <!-- 1. IN PROGRESS — the live in-flight list (active claims, all
253
- builders). Version-level progress + goals moved to the Roadmap
254
- page (task 1757) — this board stays focused on claimable work. -->
255
- <section class="scroll" id="wip-scroll" aria-labelledby="wip-h">
44
+ <!-- task 2170: one queue at a time. The four groups are hash-synced tabs
45
+ (OTBKit.makeTabs toggles [hidden] — the window stays the only
46
+ scroller): Ready (default) | In Progress | Backlog | Completed.
47
+ Deep links: /work#in-progress etc. -->
48
+ <nav id="work-tabs" aria-label="Work board sections"></nav>
49
+
50
+ <!-- READY — the claimable queue: the page's primary object, above the
51
+ fold as the default tab. -->
52
+ <section class="scroll" id="claim-scroll" aria-labelledby="claim-h">
53
+ <h2 id="claim-h" class="scroll__h">Ready — work to do<span class="count-pill" id="ready-count" hidden></span></h2>
54
+ <p class="scroll__lede">Click <span class="kbd">Claim</span> to take a task right here — no terminal needed. Then click <span class="kbd">📋</span> to copy the task prompt and paste it into a fresh Claude Code session to begin.</p>
55
+
56
+ <!-- task 2170: the filter bar is built by OTBKit.makeFilterBar —
57
+ Search / Sort / Version primary, the rest behind a "Filters"
58
+ disclosure; state rides the URL query. Control ids are unchanged
59
+ (f-search, f-sort, f-version, f-goal, f-kind, f-discipline,
60
+ f-newcomer, f-fit) so work.js reads stay stable. -->
61
+ <div id="work-filters"></div>
62
+ <p class="claim-count-line" id="claim-count" aria-live="polite"></p>
63
+
64
+ <div class="task-list" id="task-list">
65
+ <div class="profile__placeholder">…</div>
66
+ </div>
67
+ <div id="ready-pager-mount"></div>
68
+ </section>
69
+
70
+ <!-- IN PROGRESS — the live in-flight list (active claims, all builders). -->
71
+ <section class="scroll" id="wip-scroll" aria-labelledby="wip-h" hidden>
256
72
  <h2 id="wip-h" class="scroll__h">In Progress<span class="count-pill" id="wip-count" hidden></span></h2>
257
73
  <p class="scroll__lede">What is being built right now. See <a href="/roadmap">Roadmap</a> for version-level progress and goals.</p>
258
74
 
@@ -260,175 +76,29 @@
260
76
  <thead><tr><th></th><th>#</th><th>Task</th><th>Builder</th><th>For</th><th></th></tr></thead>
261
77
  <tbody><tr><td colspan="6" class="ledger__empty">…</td></tr></tbody>
262
78
  </table>
263
- <div class="pager pager--paged" id="wip-pager" hidden>
264
- <span class="pager__range" id="wip-range"></span>
265
- <div class="pager__nav">
266
- <label class="pager__perpage">
267
- <span>Per page</span>
268
- <select id="wip-per-page" aria-label="In-progress tasks per page">
269
- <option value="10">10</option>
270
- <option value="25">25</option>
271
- <option value="50">50</option>
272
- <option value="100">100</option>
273
- </select>
274
- </label>
275
- <button class="btn-ghost pager__btn" type="button" id="wip-prev" aria-label="Previous page">‹ Prev</button>
276
- <span class="pager__page" id="wip-page" aria-live="polite"></span>
277
- <button class="btn-ghost pager__btn" type="button" id="wip-next" aria-label="Next page">Next ›</button>
278
- </div>
279
- </div>
79
+ <div id="wip-pager-mount"></div>
280
80
  </section>
281
81
 
282
- <!-- 2. CLAIMABLE TASKS — the claimable queue, filterable, with the
283
- copy-prompt action (same as the hall's Claim section). -->
82
+ <!-- BACKLOG — not-yet-ready tasks (read-only). Its own tab now; the old
83
+ collapsed <details> solved the same "don't stack it" problem tabs
84
+ solve properly (task 2170). -->
284
85
  <section class="scroll" id="backlog-scroll" aria-labelledby="backlog-h" hidden>
285
- <details id="backlog-details">
286
- <summary class="backlog-summary"><span id="backlog-h" class="scroll__h">Backlog</span><span class="backlog-count" id="backlog-count"></span></summary>
287
- <p class="scroll__lede">Not yet ready — blocked by dependencies or awaiting promotion. These become claimable when their blockers ship. Click a task to see why.</p>
288
- <div class="history" id="backlog-list"></div>
289
- <div class="pager pager--paged" id="backlog-pager" hidden>
290
- <span class="pager__range" id="backlog-range"></span>
291
- <div class="pager__nav">
292
- <label class="pager__perpage">
293
- <span>Per page</span>
294
- <select id="backlog-per-page" aria-label="Backlog tasks per page">
295
- <option value="10">10</option>
296
- <option value="25">25</option>
297
- <option value="50">50</option>
298
- <option value="100">100</option>
299
- </select>
300
- </label>
301
- <button class="btn-ghost pager__btn" type="button" id="backlog-prev" aria-label="Previous page">‹ Prev</button>
302
- <span class="pager__page" id="backlog-page" aria-live="polite"></span>
303
- <button class="btn-ghost pager__btn" type="button" id="backlog-next" aria-label="Next page">Next ›</button>
304
- </div>
305
- </div>
306
- </details>
307
- </section>
308
-
309
- <section class="scroll" id="claim-scroll" aria-labelledby="claim-h">
310
- <h2 id="claim-h" class="scroll__h">Ready — work to do<span class="count-pill" id="ready-count" hidden></span></h2>
311
- <p class="scroll__lede">Click <span class="kbd">Claim</span> to take a task right here — no terminal needed. Then click <span class="kbd">📋</span> to copy the task prompt and paste it into a fresh Claude Code session to begin.</p>
312
-
313
- <div class="filters">
314
- <label class="filter filter--search">
315
- <span>Search</span>
316
- <input id="f-search" type="search" placeholder="task #, title, or goal…" aria-label="Search tasks by number, title, or goal" autocomplete="off">
317
- </label>
318
- <label class="filter">
319
- <span>Version</span>
320
- <select id="f-version"><option value="">— any —</option></select>
321
- </label>
322
- <label class="filter">
323
- <span>Goal</span>
324
- <select id="f-goal"><option value="">— all goals —</option></select>
325
- </label>
326
- <label class="filter">
327
- <span>Kind</span>
328
- <select id="f-kind">
329
- <option value="">— any —</option>
330
- <option value="feature">feature</option>
331
- <option value="bug">bug</option>
332
- <option value="infra">infra</option>
333
- <option value="refactor">refactor</option>
334
- <option value="spike">spike</option>
335
- <option value="learning-capture">learning-capture</option>
336
- <option value="cleanup">cleanup</option>
337
- <option value="decision">decision</option>
338
- <option value="blocker-resolution">blocker-resolution</option>
339
- <option value="unclassified">unclassified</option>
340
- </select>
341
- </label>
342
- <label class="filter">
343
- <span>Discipline</span>
344
- <select id="f-discipline">
345
- <option value="">— any —</option>
346
- <option value="engineer">engineer</option>
347
- <option value="artist">artist</option>
348
- <option value="ideator">ideator</option>
349
- <option value="unclassified">unclassified</option>
350
- </select>
351
- </label>
352
- <label class="filter">
353
- <span>Newcomer</span>
354
- <select id="f-newcomer">
355
- <option value="">— any —</option>
356
- <option value="yes">newcomer-friendly only</option>
357
- </select>
358
- </label>
359
- <label class="filter">
360
- <span>Run mode</span>
361
- <select id="f-fit" title="Whether a task's files overlap other visible tasks">
362
- <option value="">— any —</option>
363
- <option value="parallel">parallel-safe only</option>
364
- <option value="conflict">has file conflicts</option>
365
- </select>
366
- </label>
367
- <label class="filter">
368
- <span>Sort</span>
369
- <select id="f-sort">
370
- <option value="cpm" data-currency-tmpl="{label} / minute (high → low)">credits / minute (high → low)</option>
371
- <option value="credits" data-currency-tmpl="{label} (high → low)">credits (high → low)</option>
372
- <option value="minutes">minutes (low → high)</option>
373
- <option value="priority">priority (P0 first)</option>
374
- <option value="id">task number (low → high)</option>
375
- </select>
376
- </label>
377
- <span id="claim-count" aria-live="polite" class="filter__count"></span>
378
- </div>
379
-
380
- <div class="task-list" id="task-list">
381
- <div class="profile__placeholder">…</div>
382
- </div>
383
- <div class="pager pager--paged" id="ready-pager" hidden>
384
- <span class="pager__range" id="ready-range"></span>
385
- <div class="pager__nav">
386
- <label class="pager__perpage">
387
- <span>Per page</span>
388
- <select id="ready-per-page" aria-label="Ready tasks per page">
389
- <option value="10">10</option>
390
- <option value="25">25</option>
391
- <option value="50">50</option>
392
- <option value="100">100</option>
393
- </select>
394
- </label>
395
- <button class="btn-ghost pager__btn" type="button" id="ready-prev" aria-label="Previous page">‹ Prev</button>
396
- <span class="pager__page" id="ready-page" aria-live="polite"></span>
397
- <button class="btn-ghost pager__btn" type="button" id="ready-next" aria-label="Next page">Next ›</button>
398
- </div>
399
- </div>
86
+ <h2 id="backlog-h" class="scroll__h">Backlog<span class="backlog-count" id="backlog-count"></span></h2>
87
+ <p class="scroll__lede">Not yet ready — blocked by dependencies or awaiting promotion. These become claimable when their blockers ship. Click a task to see why.</p>
88
+ <div class="history" id="backlog-list"></div>
89
+ <div id="backlog-pager-mount"></div>
400
90
  </section>
401
91
 
402
- <!-- 3. RECENTLY SHIPPED — the last tasks shipped, so a builder can see
403
- momentum without leaving for the status dashboard. Public read
404
- surface (GET /public/recent-shipped); never gated. -->
92
+ <!-- COMPLETED — recently shipped + the project-wide momentum summary
93
+ (task 1469). Public read surface; never gated. -->
405
94
  <section class="scroll" id="history-scroll" aria-labelledby="history-h" hidden>
406
95
  <h2 id="history-h" class="scroll__h">Completed<span class="count-pill" id="done-count" hidden></span></h2>
407
- <!-- task 1469: project-wide "works completed" momentum summary — total
408
- works shipped, total currency awarded, and the latest ship. Filled
409
- by renderWorksSummary() from public reads; hidden until it loads. -->
410
96
  <div class="stat-row" id="works-summary" style="margin-bottom: 14px" hidden></div>
411
97
  <p class="scroll__lede">The most recently shipped tasks.</p>
412
98
  <div class="history" id="history-list">
413
99
  <div class="profile__placeholder">…</div>
414
100
  </div>
415
- <div class="pager pager--paged" id="done-pager" hidden>
416
- <span class="pager__range" id="done-range"></span>
417
- <div class="pager__nav">
418
- <label class="pager__perpage">
419
- <span>Per page</span>
420
- <select id="done-per-page" aria-label="Completed tasks per page">
421
- <option value="10">10</option>
422
- <option value="25">25</option>
423
- <option value="50">50</option>
424
- <option value="100">100</option>
425
- </select>
426
- </label>
427
- <button class="btn-ghost pager__btn" type="button" id="done-prev" aria-label="Previous page">‹ Prev</button>
428
- <span class="pager__page" id="done-page" aria-live="polite"></span>
429
- <button class="btn-ghost pager__btn" type="button" id="done-next" aria-label="Next page">Next ›</button>
430
- </div>
431
- </div>
101
+ <div id="done-pager-mount"></div>
432
102
  </section>
433
103
  </main>
434
104
 
@@ -444,7 +114,7 @@
444
114
  rows). work.js greys Bulk claim/release out when nothing of that kind is
445
115
  selected, and Copy parallel/sequential prompt out when the selection
446
116
  can't run that way (file/module conflicts, or an unorderable dependency
447
- cycle). -->
117
+ cycle). Selection clears on tab switch (task 2170). -->
448
118
  <div id="bulk-toolbar" class="bulk-toolbar" hidden role="region" aria-label="Bulk actions">
449
119
  <span class="bulk-toolbar__count" id="bulk-count"></span>
450
120
  <div class="bulk-toolbar__actions">
@@ -461,6 +131,8 @@
461
131
  <script src="/builders/shell.js?v=2026-07-02-shell1"></script>
462
132
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so work.js can pull from it. -->
463
133
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils" defer></script>
134
+ <!-- shared component kit (window.OTBKit) — tabs, pager, filter bar (task 2166). -->
135
+ <script src="/builders/hall-kit.js" defer></script>
464
136
  <script src="/builders/task-detail.js?v=2026-07-03-taskdetail" defer></script>
465
137
  <script src="/builders/brand-apply.js?v=2026-06-19-r56" defer></script>
466
138
  <script src="/builders/work.js?v=2026-07-03-workboard3" defer></script>