@bongos/core 1.19.878 → 1.19.880
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +43 -83
- package/docs/copy-inventory.md +368 -456
- package/docs/copy-registry.json +457 -1344
- package/docs/file-map.md +2 -2
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/module.json +1 -1
- package/modules/hall-ui/public/builders.js +1 -13
- package/modules/hall-ui/public/dom-utils.js +22 -6
- package/modules/hall-ui/public/goals-render.js +8 -3
- package/modules/hall-ui/public/hall-render.js +2 -18
- package/modules/hall-ui/public/index.html +0 -3
- package/modules/hall-ui/public/panel.css +8 -9
- package/modules/hall-ui/public/settings.css +0 -5
- package/modules/hall-ui/public/settings.html +0 -29
- package/modules/hall-ui/public/settings.js +1 -26
- package/modules/hall-ui/public/shell.js +0 -1
- package/modules/hall-ui/public/style.css +0 -44
- package/modules/hall-ui/public/task.js +6 -2
- package/modules/hall-ui/public/watch.html +0 -7
- package/modules/hall-ui/public/watch.js +1 -37
- package/modules/hall-ui/public/work.js +4 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/bongos/serve-internal.js +11 -11
- package/src/module-api.js +1 -1
- package/tests/government_page_gates.mjs +1 -1
- package/tests/hall_landing_boot.mjs +1 -1
- package/tests/hall_nav.mjs +1 -1
- package/tests/hall_oversight_world.mjs +5 -5
- package/tests/hall_page_gate_map.mjs +11 -2
- package/tests/hall_record_world.mjs +5 -0
- package/tests/hall_settings_world.mjs +21 -18
- package/tests/kind_axis_unset.mjs +195 -0
- package/modules/hall-ui/public/box-panel.js +0 -456
- package/modules/hall-ui/public/harbor.css +0 -9
- package/modules/hall-ui/public/harbor.html +0 -69
- package/modules/hall-ui/public/harbor.js +0 -367
- package/modules/hall-ui/public/harbor.states.json +0 -77
- package/modules/hall-ui/public/pair.css +0 -23
- package/modules/hall-ui/public/pair.html +0 -58
- package/modules/hall-ui/public/pair.js +0 -132
- package/modules/hall-ui/public/pair.states.json +0 -14
package/docs/file-map.md
CHANGED
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
│ ├── sessions/ ← CORE-DOMAIN carve (BV1.R82, default-on): the session_records corpus + data plane (upload, cross-builder search/deep-dive), the BFG read-the-room scorer, session-pulse/stale-claim helpers. Registers no port — reached via HTTP POST to its own /sessions route; resolves the economy `reward` port for the cost-plus token reward. CLAUDE.md, module.json, routes/sessions.js, bfg.js, pulse.js.
|
|
136
136
|
│ ├── autonomy/ ← CORE-DOMAIN carve (BV1.R83, default-on): the MAS autonomy surfaces — the $0 deterministic autonomy gate (System 3, inert until armed), the conductor/architect CLIs, and the in-process routine timers (incl. the weekly peer-vote-tally poller). Registers no port; resolves the lifecycle `tallyPeerVotes` doorway. CLAUDE.md, module.json, routes/autonomy.js, autonomy.js.
|
|
137
137
|
│ ├── status-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R84, default-on): the public status dashboard at status.<apex>, moved from public-status/. NO routes/db/port — declares contributes.webSurfaces:[{host:"status.",dir:"public"}], served by the loader web-surface seam (moduleWebSurfaces → serve-internal). CLAUDE.md, module.json, public/{index.html,status.js,style.css,cursors/,snapshots/}.
|
|
138
|
-
│ ├── hall-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R85, default-on): the authenticated builders' hall at builders.<apex>, moved from public-builders/ (~13k LOC, the largest). NO routes/db/port — declares contributes.webSurfaces:[{host:"builders.",dir:"public"}] for discovery, but UNLIKE status-ui keeps its DEDICATED serving block in serve-internal (the /builders shim + canonical redirects + citizen/Archon page gates + asset-stamping + hall-widget injection), partitioned out of the generic web-surface loop and served from BUILDERS_DIR. CLAUDE.md, module.json, public/{index.html,builders.js,style.css,work,watch,
|
|
138
|
+
│ ├── hall-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R85, default-on): the authenticated builders' hall at builders.<apex>, moved from public-builders/ (~13k LOC, the largest). NO routes/db/port — declares contributes.webSurfaces:[{host:"builders.",dir:"public"}] for discovery, but UNLIKE status-ui keeps its DEDICATED serving block in serve-internal (the /builders shim + canonical redirects + citizen/Archon page gates + asset-stamping + hall-widget injection), partitioned out of the generic web-surface loop and served from BUILDERS_DIR. CLAUDE.md, module.json, public/{index.html,builders.js,style.css,work,watch,gate,settings,ranks,sessions,primer,diagrams,atlas,...}.{html,js},cursors/,chime.wav. Four ARCHETYPE sheets sit beside the per-page ones: `record.css` (the task + idea records, task 1003305), `room.css` (the READING ROOMS — the primer + the diagrams index, task 1003306: the reading measure and rhythm, the table of contents, the progress hairline and the framed figure diagram-viewer.js upgrades on both pages), `oversight.css` (the OVERSIGHT family — government, watch, gate, task 1003469 (harbor was its fourth until task 1003890 removed the dev box): the row, the figure band inside a panel, the group head, the inline form, the grant toggle and the shared confirm modal; named oversight because the vocabulary wall bans "governance" on the government surface) and `panel.css` (the PANEL family — settings, profile, task 1003308 (pair was its third until task 1003890 removed the dev box): the row, the switch, the field with its label above, the chip control, the four voices and the sign-in gate; the hall's my-projects page was DELETED in the same task — "my projects" is the hub's user-level page, and the hall keeps no link or redirect; the family's fourth page `not-ready.html` was deleted by task 1003450, along with the emptied `requireNonXenosPage` gate that was the only thing redirecting to it). A page sheet then holds only what one page has and the others do not — `primer.css` the acknowledge gate, `diagrams.css` the legend strip, `gate.css` the hold reasons and file chips, `watch.css` the severities, the report reader and the grade trend, `settings.css` the rail layout, the group head, the token ladder and the voices grid, `profile.css` the identity band and the shelf, `people.css` the directory's identity cell (task 1003470 made the legacy door `/scouting` ship the same body and script as `/people`; task 1003440 then deleted the door — `scouting.html` and `scouting.states.json` are gone and the URL 301s to `/people`).
|
|
139
139
|
│ ├── lifecycle/ ← CORE-DOMAIN carve (BV1.R86, default-on): the build state machine — tasks · claims · versions · done-when · goals · dependencies · claim→ship→grade→credit · github-push + merge-lock + conflict-resolve + publish-reconciler. The LAST, most-coupled carve; registers the `lifecycle` kernel port (createTask, classifyTaskKind, tallyPeerVotes, work-tracking reads). CLAUDE.md, module.json, routes/{tasks,claims,versions,done-when,goals,dependencies,gate-approvals,analytics}.js, lifecycle.js, github-push.js, merge-lock.js, conflict-resolve.js, publish-reconciler.js, task-visuals.js + task-visual-db.js + routes/visuals.js (the optional ship-time visual, task 1003109 — the route file is NOT named task-*.js on purpose; see the module CLAUDE.md).
|
|
140
140
|
│ ├── copy-desk/ ← CORE-DOMAIN module (task 1003113 / R02 of goal 1000074, default-on): the COPY half of the design contract — ADR 0081 gave design TOKENS a repo-owned source of truth, text had none. Owns the FLAG (anyone in any role marks a string or a whole surface as needing an artist's attention, with a reason required in BOTH the route and a CHECK constraint) and the QUEUE an artist reads it from. READS R01's committed registry (docs/copy-registry.json, generated by scripts/gds/copy-inventory.js) and never writes it. NO LIVE CMS is the hard non-goal: no column here could hold replacement text, and copy_no_cms.mjs pins that. Key is `copy-desk`, not `copy` — the branding contract already owns a `copy` block, so the bare word reds the "core carries no module code" fitness check. R03 (task 1003114, ADR 0233) added the PROPOSAL: an artist writes the replacement wording and it becomes a Bongos task carrying a fenced copy-proposal patch — no row, NO second migration (a proposals table is the forbidden column with extra steps), and scripts/gds/copy-apply.js lands it as a real diff under a claim. CLAUDE.md, module.json, registry.js, flags.js, proposals.js, routes/copy-desk.js, migrations/copy_desk_001_flags.sql, tests/{copy_flags,copy_queue,copy_no_cms,copy_proposals}.mjs. Its hall surface lives with hall-ui (public/copy-desk.{html,js,css}), per the one-key-per-web-surface precedent.
|
|
141
141
|
│ ├── ui-design/ ← CORE-DOMAIN module (task 1003324 / ADR 0197, default-on): the design capability every builder on every instance gets — ships METHOD, never a world. Absorbs ADR 0081's layer: adapters/{claude-design,figma}/index.js (moved from src/ui/adapters/), scripts/{design-sync,figma-design-sync,validate-design}.js (moved from scripts/gds/, which keeps thin shims), docs/design-contract.md (moved from docs/). Declaration-only: contributes.skills design (the /design playbook, new) + design-sync + figma-design-sync; no routes/port/migrations, so disabling it touches no served surface. CLAUDE.md separates the platform FLOORS (the Fifteen Rule, the dark twins, no page :root, the 24px floor, AA in both modes, the kill switch) from the instance's WORLD (its packs + DESIGN.md). kit/ (task 1003320) is the look-before-you-ship kit: lib.js (the floors, the states/probes contracts, the action + expectation vocabularies, the WCAG maths, the stub spawner), serve.js (any surface through the doorway's real transforms + fixtures/), render.js (states × 1440/390/320 × dark/light, audited), probe.js (PASS/FAIL contracts), check-mock.js (platform rules + the instance's DESIGN.md taste bans, then the detector), tells.js (task 1003329 / ADR 0223: the anti-pattern detector as two tiers — floors FAIL, craft tells WARN, kit-ignore waivers per file; the rendered twins live in lib.js factsInPage), contrast.js + png.js; a page's <page>.states.json / <page>.probes.json sit BESIDE the surface (modules/public-landing/public/, modules/hall-ui/public/). Recipe: docs/recipes/ui-look-before-you-ship.md. skills/ (task 1003321 / ADR 0198) is the vendoring policy: policy.json (licence allowlist, verdicts that may land, sidecar fields, preamble markers), PREAMBLE.md (the platform preamble every vendored SKILL.md opens with), README.md (the roster — both origins scanned dangerous on 2026-08-28, landed as rebuild specs; nothing vendored — and the landing recipe); a landable copy goes under skills/vendor/<name>/ with PROVENANCE.md + LICENSE and is materialised into an instance's .claude/skills/ by claude-materialize.js step 1b. skills/<name>/ (task 1003325 / ADR 0220) are the in-house rebuilds from the specs, first-party and counted: design-taste-frontend (the default taste skill), design-taste-frontend-v1 (the earlier generation, kept distinct), high-end-visual-design (the polish pass), redesign-existing-projects (the in-place upgrade); each opens with the same preamble and carries a "Rebuilt from" section instead of a sidecar. impeccable/ (task 1003326 / ADR 0221) is the design-craft method as ONE skill with sub-commands: SKILL.md (the router, the menu, the craft floor, the bounded finish) + reference/<sub-command>.md (eighteen playbooks, one loaded per request); no hooks, no bypass agent, no telemetry, no live server. minimalist-ui/, industrial-brutalist-ui/, gpt-taste/, stitch-design-taste/ (task 1003327 / ADR 0230) are the four looks, composition grammars with no colours of their own: the palette is the instance's pack and the texture is a named entry in styles/; a substrate is an archetype that still ships both modes, gpt-taste's selection is derived from the route rather than rolled, and stitch-design-taste writes a DESIGN.md-shaped contract document whose thirteen are transcribed from the pack. image-to-code/, imagegen-frontend-web/, imagegen-frontend-mobile/, brandkit/ (task 1003328 / ADR 0222) are the image family under the hero-only rule: plates and hero objects only, the pair (JPEG dark plate + WebP alpha cutout) with a <file>.json sidecar beside each, through the instance's art pipeline key; the grove specimen's styles/grove/assets/ is the worked example. style/ (task 1003475 / ADR 0231) is the module's first FIRST-PARTY skill (no upstream, so a `## First party` section instead of `## Rebuilt from`): the /style session in which an owner authors their own look in four bounded steps, rendering the nearest library entries before asking, drafting inside the contract, retuning by measurement, and handing over the one-step adoption without ever writing config/branding.json. styles/ (task 1003323 / ADR 0219) is the style library: <name>/pack.json (the theme.ui overlay, exactly the fifteen) + DESIGN.md (the look's derived recipes, thirteen in lockstep with the pack) + mock.html (the specimen); chrome-world (pinned to the neutral pack), expedition, grove, blueprint (the first cool look, authored through /style at task 1003475); STYLE=<name> on the kit lays a look over the instance's pack through GDS_BRANDING_FILE; tests/ui_design_styles.mjs runs the world/cosmos/hall token suites once per alternate (UI_DESIGN_PACK). config/design-tokens.* + design-sources.json STAY in config/ as the host boundary; public-landing keeps its own key (first customer, not owner).
|
|
@@ -265,7 +265,7 @@
|
|
|
265
265
|
│ ├── terrain.js ← (Phase D + ADR 0012, CJS): TERRAIN + OBJECT enums + BLOCKING_TERRAINS + BLOCKING_OBJECTS (server twin of public/game/world/terrain.js)
|
|
266
266
|
│ └── map.js ← (Phase D + ADR 0012): two-grid INITIAL_MAP {ground, objects}; isBlocked checks both layers (mirrors public/game/world/{terrain,map}.js)
|
|
267
267
|
│ (public-status/ moved to modules/status-ui/public/ in BV1.R84 — see the modules/ block above)
|
|
268
|
-
│ (public-builders/ moved to modules/hall-ui/public/ in BV1.R85 — the authenticated builders' hall; see the modules/ block above. It keeps its DEDICATED serving block in src/bongos/serve-internal.js: the builders.<apex> + apex /builders/* shim, canonical redirects, the citizen/Archon page gates, asset-stamping, and the module hall-widget injection — partitioned out of the generic web-surface loop. index.html=the hall dashboard; work/board/roadmap/goals/watch/
|
|
268
|
+
│ (public-builders/ moved to modules/hall-ui/public/ in BV1.R85 — the authenticated builders' hall; see the modules/ block above. It keeps its DEDICATED serving block in src/bongos/serve-internal.js: the builders.<apex> + apex /builders/* shim, canonical redirects, the citizen/Archon page gates, asset-stamping, and the module hall-widget injection — partitioned out of the generic web-surface loop. index.html=the hall dashboard; work/board/roadmap/goals/watch/gate/settings/ranks/sessions/primer/diagrams/atlas pages (harbor + pair left with the dev box, task 1003890); ideas.{html,js,css}=the Full Idea composer (task 1002928 / R152 of goal 1000062 — the five R141 fields with a live R142 completeness meter, both fetched from the server so the page carries no copy of the rules; drafts in localStorage so navigation costs nothing. Task 1002930 / R154 added the SPARK QUEUE above it and a second mode: `?develop=<id>` reuses the same form to develop a spark — the spark's words shown above the fields, its title read-only, and the file routed to POST /inbox/:id/develop instead of POST /inbox, under its own per-idea draft key); idea.html/idea.js=the idea-detail PAGE (/idea/:id, task 1002929 / R153 — the SECOND two-segment hall page after /task/:id: grade, the five answers in template order, the score, and both attributions. The GRADE decides what the page contains — a quick idea gets no five-field skeleton. task-detail.js keeps the #/idea/N overlay because ~320 of its lines are the Metic+ triage panel; the overlay now links here); profile.html/profile.js=the public, shareable builder profile page (/profile?id=N — rank, works, credits, karma, achievements; task 1467); profile-connections.js=section 6 of that page, the hub-only connections block (task 1002296 / R20 of goal 1000045 — the viewer-relative 1st/2nd/3rd/out-of-network label, the mutuals it was computed from, the connect button, and on your own profile both request queues plus your connections ledger. Loaded BEFORE profile.js, which calls window.OTBConnections.render behind a guard, so a page that omits the script simply has no section; the section reveals only when the hub's /connections routes answer, exactly as the cross-project record does. ADR 0212 records why it is on this page rather than the not-yet-built /u/<handle>, and why it addresses a builder by github_login and then uses the canonical handle the API echoes back); profile-canonical.js=the canonical-profile wiring for that page (task 1002804 / P08, ADR 0214 — on a FEDERATED instance the rel=canonical plus the visible "see the cross-project record" link-out ADR 0171 D1 asks for; on the HUB the numeric ?id= form redirects to the handle URL instead, because a page cannot both redirect to a URL and declare it canonical. All three read ONE resolver, modules/platform-identity/canonical-profile.js, which answers null while /u/<handle> does not exist — so everything is dark today and one boolean turns it all on together); task.html/task.js=the task-detail page (/task/:id, task 751 — replaced the old #/task/N overlay); builders.js=the controller; dom-utils.js/hall-widgets.js=the widget+settings-panel registries.)
|
|
269
269
|
│
|
|
270
270
|
├── infra/ ← ON-BOX scripts (task 1002699): the four reporter/heartbeat crons every dev box runs from its /workspace clone — box-heartbeat.sh (idle-sweep activity signal), box-report-version.sh (HEAD → POST /box/version), box-report-host-keys.sh (SSH host keys → POST /box/host-keys), box-report-terminal.sh (ttyd URL+credential → POST /box/terminal). Delivered by the workspace clone itself (modules/dev-box/box-access.js sparse scope includes infra/); crons self-installed by box-source-fetch.sh's per-tick bring-up. API base resolves GDS_BASE env → session-file api_base → skip (no hardcoded host in the neutral core).
|
|
271
271
|
├── devbox-app/ ← OTB Dev Box — Electron menu-bar/tray switch for the builder's box (#904, ADR 0045; internal). SELF-CONTAINED: own package.json (never feeds the droplet's npm ci); built by .github/workflows/build-devbox-app.yml; published to the public releases repo per config/devbox-app.json; release recipe docs/recipes/devbox-app-release.md
|
|
@@ -2230,5 +2230,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2230
2230
|
landed since 1.19.876 with no explicit bump. run 35438492966. (task 1002620)
|
|
2231
2231
|
1.19.878 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2232
2232
|
landed since 1.19.877 with no explicit bump. run 35439004814. (task 1002620)
|
|
2233
|
+
1.19.879 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2234
|
+
landed since 1.19.878 with no explicit bump. run 35439529685. (task 1002620)
|
|
2235
|
+
1.19.880 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2236
|
+
landed since 1.19.879 with no explicit bump. run 35453118533. (task 1002620)
|
|
2233
2237
|
---------------------------------------------------------------------------
|
|
2234
2238
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"key": "hall-ui",
|
|
3
3
|
"title": "Builders' Hall",
|
|
4
|
-
"description": "The authenticated builders' hall served at builders.<apex> (builders.example.com) — the roster, work board, standing/karma, leaderboard, achievements, primer, system maps, settings,
|
|
4
|
+
"description": "The authenticated builders' hall served at builders.<apex> (builders.example.com) — the roster, work board, standing/karma, leaderboard, achievements, primer, system maps, settings, and the Archon-only watch/gate pages, all polling /api/bongos/* and the read-only /api/bongos/public/* surface. The largest WEB-SURFACE core-domain module (~13k LOC), carved out of the GDS core in BV1.R85 (ADR 0093 §1; 02-module-map §6). default-on: a Cloud Bongos instance ships its hall like it ships its status page. Registers no port and contributes no routes — it declares a webSurface (host prefix + static dir). Unlike the generic status surface, the hall keeps its dedicated serving block in serve-internal.js (the builders.<apex> + apex /builders/* shim, canonical redirects, the citizen/Archon page gates, asset-stamping, and the module hall-widget injection) — the webSurfaces declaration is the discovery + scope-map + window.__MODULES__ record; serve-internal serves it from this module's public/ dir with that richer machinery. The me/public/leaderboard read endpoints it renders stay SHARED core in routes/{me,public,builders}.js (the status surface + the off-box mirror read them too).",
|
|
5
5
|
"coreVersion": "^1.11.0",
|
|
6
6
|
"default": true,
|
|
7
7
|
"maintenance": { "status": "core-maintained" },
|
|
@@ -408,15 +408,6 @@
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
|
|
411
|
-
// #777/#783/#807: the dev-box management UI now lives in the shared OTBBoxPanel
|
|
412
|
-
// module (public-builders/box-panel.js) so it can be reused verbatim on the
|
|
413
|
-
// Settings page. Here it runs in browser-only mode (showSsh:false) — a newcomer
|
|
414
|
-
// sees only the online terminal, never raw SSH details. We hold ONE instance;
|
|
415
|
-
// it owns its own self-rescheduling poll + terminal-window handle. Lazily
|
|
416
|
-
// created so it survives the very first renderWelcome regardless of which
|
|
417
|
-
// <script> finished loading first; a no-op shim keeps callers safe if the
|
|
418
|
-
// module somehow failed to load.
|
|
419
|
-
|
|
420
411
|
// ---- onboarding checklist (V3.R75 #294; reshaped #777) ------------------
|
|
421
412
|
// Renders the "Path into the City" checklist for the CURRENT logged-in
|
|
422
413
|
// builder. Hidden once graduated (current_stage === 'graduated') so it
|
|
@@ -1284,8 +1275,6 @@
|
|
|
1284
1275
|
|
|
1285
1276
|
// #777: setup-config toggle in the welcome panel. Flips which config pane
|
|
1286
1277
|
// (Desktop app vs Claude Online) is shown — pure client-side, no round-trip.
|
|
1287
|
-
// The dev-box buttons + credential-copy inside the online pane are handled by
|
|
1288
|
-
// the OTBBoxPanel module's own scoped listener (#807), not here.
|
|
1289
1278
|
$('#welcome-body')?.addEventListener('click', (e) => {
|
|
1290
1279
|
const tab = e.target.closest('.setup__tab[data-config]');
|
|
1291
1280
|
if (!tab) return;
|
|
@@ -1305,7 +1294,6 @@
|
|
|
1305
1294
|
if (!scroll) return;
|
|
1306
1295
|
const minimized = scroll.classList.toggle('scroll--welcome--minimized');
|
|
1307
1296
|
if (btn) btn.textContent = minimized ? '+' : '−';
|
|
1308
|
-
if (minimized) onboardingBox().stop(); else onboardingBox().refresh();
|
|
1309
1297
|
});
|
|
1310
1298
|
|
|
1311
1299
|
// V3.R25 (#245): delegated click handler for the peer-acclaim vote buttons.
|
|
@@ -1425,7 +1413,7 @@
|
|
|
1425
1413
|
// reads what this page holds NOW rather than what it held at boot. Everything
|
|
1426
1414
|
// else is stable for the life of the page. This call sits AFTER every
|
|
1427
1415
|
// declaration it passes — moving it earlier is a temporal-dead-zone crash.
|
|
1428
|
-
const { SETUP_CONFIG_KEY, acclaimEvidenceHtml, analyticsState, lbState, mountHallWidgets,
|
|
1416
|
+
const { SETUP_CONFIG_KEY, acclaimEvidenceHtml, analyticsState, lbState, mountHallWidgets, renderCurveBody, renderGreeting, renderLanding, renderNav, renderOnboarding, renderProfile, renderRecentShips, renderWelcomeCore, shipState, shipsPager, welcomeDismissalKey } = window.OTBHallRender({
|
|
1429
1417
|
API, RANK_ORDER, api, brandWorld, curLabel, emptyRow, fmtDate, mins, normalizeRank, pct, postJSON, rankLabel, rankWeight, signClasses, toast, usd,
|
|
1430
1418
|
get instanceRepo() { return instanceRepo; },
|
|
1431
1419
|
get lastClaimableCount() { return lastClaimableCount; },
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
// NOT a consumer: modules/status-ui/public/ (the off-box status mirror) stays
|
|
7
7
|
// self-contained by design — do not wire this there. Network helpers
|
|
8
8
|
// (getJSON/postJSON/patchJSON) and renderRankBadge are deliberately NOT here:
|
|
9
|
-
// the former carry auth-redirect drift that differs per page
|
|
10
|
-
//
|
|
9
|
+
// the former carry auth-redirect drift that differs per page, the latter is
|
|
10
|
+
// single-use and coupled to
|
|
11
11
|
// the rank-ladder constant (a D1 concern). See
|
|
12
12
|
// docs/audits/2026-06-14-repo-cleanup-audit.md §2A/§2B (frontend-utils).
|
|
13
13
|
//
|
|
@@ -146,7 +146,10 @@
|
|
|
146
146
|
for (const k of list) {
|
|
147
147
|
const opt = document.createElement('option');
|
|
148
148
|
opt.value = k;
|
|
149
|
-
|
|
149
|
+
// The unset bucket is named for a reader on EVERY surface, filters included
|
|
150
|
+
// — `label` is the caller's choice for the real kinds, never for this one
|
|
151
|
+
// (task 1004038). roleOptions() names the role twin the same way.
|
|
152
|
+
opt.textContent = kindIsUnset(k) ? kindLabel(k) : label(k);
|
|
150
153
|
sel.appendChild(opt);
|
|
151
154
|
}
|
|
152
155
|
// A refill must not drop the reader's pick; `selected` is the filing default.
|
|
@@ -154,10 +157,23 @@
|
|
|
154
157
|
if (want) sel.value = want;
|
|
155
158
|
}
|
|
156
159
|
|
|
160
|
+
// A task with no kind carries the DB default 'unclassified' — the twin of
|
|
161
|
+
// ROLE_UNSET one axis over (task 1004038, filed by task 1003936 which fixed the
|
|
162
|
+
// role axis and left this one). A word a column chose is not a word a person
|
|
163
|
+
// should read (docs/voice.md V2), so a picker shows "No kind yet" and a row tag
|
|
164
|
+
// renders NOTHING. kindIsUnset() is how a caller asks. The STORED value and the
|
|
165
|
+
// filter VALUE stay 'unclassified'; only what is read changes.
|
|
166
|
+
const KIND_UNSET = 'unclassified';
|
|
167
|
+
function kindIsUnset(k) { return !k || String(k) === KIND_UNSET; }
|
|
168
|
+
|
|
169
|
+
// NOT ESCAPE-SAFE: like roleLabel() below, this returns a transformed copy of
|
|
170
|
+
// its input, so a caller rendering it into markup must escapeHtml() the result.
|
|
171
|
+
// Every caller today assigns it to textContent, which escapes for them.
|
|
157
172
|
// How a kind is named in a picker — 'blocker-resolution' → 'Blocker resolution'.
|
|
158
173
|
// The same shape roleLabel takes below, and it reproduces every label the
|
|
159
174
|
// hand-written <option> list in ideas.html carried, so no copy changes.
|
|
160
175
|
function kindLabel(k) {
|
|
176
|
+
if (kindIsUnset(k)) return 'No kind yet';
|
|
161
177
|
const s = String(k || '').replace(/-/g, ' ');
|
|
162
178
|
return s ? s.charAt(0).toUpperCase() + s.slice(1) : '';
|
|
163
179
|
}
|
|
@@ -212,8 +228,8 @@
|
|
|
212
228
|
// Module→core settings-panel contribution seam (BV1.R42, ADR 0083) — the
|
|
213
229
|
// browser twin of the server's 'profile.fields' seam (src/module-seams.js). A
|
|
214
230
|
// module that has left core registers a Settings panel from its own client
|
|
215
|
-
// script (loaded before settings.js
|
|
216
|
-
//
|
|
231
|
+
// script (loaded before settings.js); settings.js then renders every
|
|
232
|
+
// registered panel instead of hardcoding discord/art.
|
|
217
233
|
// Empty until a module registers → the page renders exactly what it does today.
|
|
218
234
|
// A panel: { id, title?, order?, mount(el) } — mount() is handed a container
|
|
219
235
|
// element to render into. order sorts ascending (default 0).
|
|
@@ -407,7 +423,7 @@
|
|
|
407
423
|
escapeHtml, $, fmtNum, num, fmtInt, fmtCompact, fmtDate, rankLabel, toast, moduleOn, disciplines,
|
|
408
424
|
// task 1003936 — ONE word for the role axis, all six surfaces
|
|
409
425
|
roleAxisLabel, roleLabel, roleOptions, roleIsUnset, ROLE_UNSET,
|
|
410
|
-
fillKindFilter, kindLabel, // task 1003453 — one Kind filler, all three surfaces
|
|
426
|
+
fillKindFilter, kindLabel, kindIsUnset, KIND_UNSET, // task 1003453 — one Kind filler, all three surfaces
|
|
411
427
|
errCode, errMessage, errDetails, // task 1002462 — ADR 0116 envelope readers
|
|
412
428
|
contributeSettingsPanel, settingsPanels,
|
|
413
429
|
contributeHallWidget, hallWidgets, hallWidgetIds,
|
|
@@ -321,6 +321,11 @@
|
|
|
321
321
|
const disciplineTag = window.OTB.roleIsUnset(t.discipline)
|
|
322
322
|
? ''
|
|
323
323
|
: `<span class="task__tag">${escapeHtml(window.OTB.roleLabel(t.discipline))}</span>`;
|
|
324
|
+
// A kind nobody set is no tag at all, not the column's default word — the
|
|
325
|
+
// role tag above is the precedent this follows (task 1004038).
|
|
326
|
+
const kindTag = window.OTB.kindIsUnset(t.kind)
|
|
327
|
+
? ''
|
|
328
|
+
: `<span class="task__tag">${escapeHtml(t.kind)}</span>`;
|
|
324
329
|
const newcomerTag = t.newcomer_friendly ? '<span class="task__tag task__tag--newcomer">newcomer</span>' : '';
|
|
325
330
|
const rankTag = rankTagHtml(t.requires_rank);
|
|
326
331
|
const touches = Array.isArray(t.touches) ? t.touches : [];
|
|
@@ -361,7 +366,7 @@
|
|
|
361
366
|
<p class="task__title"><a class="task__link" href="${escapeHtml(taskHref(id))}">${escapeHtml(t.title || '')}</a></p>
|
|
362
367
|
<div class="task__meta">
|
|
363
368
|
<span class="task__tag">${escapeHtml(t.version_id || '?')}</span>
|
|
364
|
-
|
|
369
|
+
${kindTag}
|
|
365
370
|
${disciplineTag}
|
|
366
371
|
${newcomerTag}
|
|
367
372
|
${rankTag}
|
|
@@ -403,7 +408,7 @@
|
|
|
403
408
|
<tr class="ledger__row--task" data-task-id="${escapeHtml(String(t.id))}" style="cursor:pointer" title="Open task #${escapeHtml(String(t.id))}">
|
|
404
409
|
<td class="ledger__num">#${escapeHtml(String(t.id))}</td>
|
|
405
410
|
<td>${escapeHtml(t.title || '')}</td>
|
|
406
|
-
<td>${
|
|
411
|
+
<td>${window.OTB.kindIsUnset(t.kind) ? '—' : escapeHtml(t.kind)}</td>
|
|
407
412
|
<td class="ledger__drachmae">${fmtNum(creditVal(t))}${taskSettled(t) ? '' : ' <span class="ledger__est" title="Estimate — credits settle when the task is confirmed">est.</span>'}</td>
|
|
408
413
|
<td class="ledger__date">${fmtDate(t.shipped_at)}</td>
|
|
409
414
|
</tr>`).join('');
|
|
@@ -502,7 +507,7 @@
|
|
|
502
507
|
const sortBy = $('#f-goal-sort')?.value || 'cpm';
|
|
503
508
|
let list = state.work.todo.filter((t) => {
|
|
504
509
|
if (!matchesTodoSearch(t, sQuery)) return false;
|
|
505
|
-
if (kFilter && (t.kind ||
|
|
510
|
+
if (kFilter && (t.kind || window.OTB.KIND_UNSET) !== kFilter) return false;
|
|
506
511
|
if (dFilter && (t.discipline || window.OTB.ROLE_UNSET) !== dFilter) return false;
|
|
507
512
|
if (nFilter === 'yes' && !t.newcomer_friendly) return false;
|
|
508
513
|
return true;
|
|
@@ -854,9 +854,7 @@
|
|
|
854
854
|
<div class="setup__pane setup__pane--online">
|
|
855
855
|
<ol class="setup__steps">
|
|
856
856
|
<li><strong>Create your <a href="https://claude.com" target="_blank" rel="noopener noreferrer">Claude</a> account.</strong></li>
|
|
857
|
-
<li><strong>Open your online environment.</strong> This is the environment you will build in — no SSH, nothing to install
|
|
858
|
-
<div class="setup__box" data-box-panel></div>
|
|
859
|
-
</li>
|
|
857
|
+
<li><strong>Open your online environment.</strong> This is the environment you will build in — no SSH, nothing to install.</li>
|
|
860
858
|
<li><strong>Sign in when Claude prompts you.</strong> Claude starts automatically when you open the terminal.
|
|
861
859
|
<span class="setup__hint">To paste the sign-in code: <strong>Ctrl+Shift+V</strong> or right-click — plain Ctrl+V will not paste here. Claude takes over the terminal with its own interface once you're signed in. This guide stays open in its own tab. If Claude didn't start automatically, type <code>claude</code> and press Enter.</span></li>
|
|
862
860
|
<li><strong>Then drive it however you like:</strong>
|
|
@@ -912,20 +910,6 @@
|
|
|
912
910
|
// Remember the stage we rendered for, so the dismiss handler can record it.
|
|
913
911
|
scroll.dataset.stageIdx = String(currentIdx);
|
|
914
912
|
scroll.hidden = false;
|
|
915
|
-
// #783/#807: mount the shared dev-box panel into the online pane and paint
|
|
916
|
-
// it from live server state. Browser-only onboarding hides SSH details
|
|
917
|
-
// (showSsh:false) — a newcomer sees only the online terminal. The panel runs
|
|
918
|
-
// its own poll while anything is in flight (survives tab flips / re-renders /
|
|
919
|
-
// reloads / background approvals); mount re-binds to the freshly-rendered DOM.
|
|
920
|
-
const boxMount = body.querySelector('[data-box-panel]');
|
|
921
|
-
if (boxMount) onboardingBox().mount(boxMount);
|
|
922
|
-
}
|
|
923
|
-
let _onboardingBox = null;
|
|
924
|
-
function onboardingBox() {
|
|
925
|
-
if (!_onboardingBox && window.OTBBoxPanel) {
|
|
926
|
-
_onboardingBox = window.OTBBoxPanel.create({ api: API, showSsh: false, toast });
|
|
927
|
-
}
|
|
928
|
-
return _onboardingBox || { mount() {}, refresh() {}, stop() {} };
|
|
929
913
|
}
|
|
930
914
|
function renderOnboarding(onboarding, discord) {
|
|
931
915
|
const scroll = $('#onboarding-scroll');
|
|
@@ -1351,6 +1335,6 @@
|
|
|
1351
1335
|
return idx === -1 ? null : { place: idx + 1, total: ranked.length };
|
|
1352
1336
|
}
|
|
1353
1337
|
|
|
1354
|
-
return { SETUP_CONFIG_KEY, acclaimEvidenceHtml, analyticsState, lbState, mountHallWidgets,
|
|
1338
|
+
return { SETUP_CONFIG_KEY, acclaimEvidenceHtml, analyticsState, lbState, mountHallWidgets, renderCurveBody, renderGreeting, renderLanding, renderNav, renderOnboarding, renderProfile, renderRecentShips, renderWelcomeCore, shipState, shipsPager, welcomeDismissalKey };
|
|
1355
1339
|
};
|
|
1356
1340
|
})();
|
|
@@ -105,9 +105,6 @@
|
|
|
105
105
|
<script src="/builders/shell.js?v=2026-07-02-shell1" defer></script>
|
|
106
106
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
107
107
|
<script src="/builders/palette.js" defer></script>
|
|
108
|
-
<!-- #807: shared dev-box management panel — loaded BEFORE builders.js so the
|
|
109
|
-
OTBBoxPanel global is defined when the welcome panel mounts it. -->
|
|
110
|
-
<script src="/builders/box-panel.js?v=2026-06-14-domutils" defer></script>
|
|
111
108
|
<!-- task 2166: the shared component kit (window.OTBKit) — pager/ledger/rail.
|
|
112
109
|
Loaded BEFORE hall-widgets.js, whose skeletons call OTBKit.pagerBarHtml(). -->
|
|
113
110
|
<script src="/builders/hall-visual.js?v=2026-09-16-visual1" defer></script>
|
|
@@ -48,9 +48,8 @@
|
|
|
48
48
|
.settings-card__hint { font-size: 13px; color: var(--ink-faint); }
|
|
49
49
|
.panel-status,
|
|
50
50
|
.settings-status,
|
|
51
|
-
.
|
|
52
|
-
.panel-status--
|
|
53
|
-
.panel-status--danger, .pair-status--err { color: var(--danger); }
|
|
51
|
+
.panel-status--ok, .settings-card__ok { color: var(--ok); }
|
|
52
|
+
.panel-status--danger { color: var(--danger); }
|
|
54
53
|
.panel-status:empty, .settings-status:empty { margin-top: 0; min-height: 0; }
|
|
55
54
|
/* a prose link in any of the four voices is a control and owes the 24px floor */
|
|
56
55
|
.panel-lede a, .panel-note a, .panel-hint a, .panel-status a, .settings-card__hint a, .section-note a {
|
|
@@ -114,7 +113,7 @@
|
|
|
114
113
|
accent door — the panel's one primary act — and takes --accent-on, the dark
|
|
115
114
|
ink for the salmon; white on it fails AA and DESIGN.md bans it. */
|
|
116
115
|
.pbtn,
|
|
117
|
-
.settings-btn, .sessions-row__end, .event-sound-preview
|
|
116
|
+
.settings-btn, .sessions-row__end, .event-sound-preview {
|
|
118
117
|
display: inline-flex;
|
|
119
118
|
align-items: center;
|
|
120
119
|
justify-content: center;
|
|
@@ -135,14 +134,14 @@
|
|
|
135
134
|
transition: background 200ms cubic-bezier(.2,.7,.3,1), border-color 200ms cubic-bezier(.2,.7,.3,1), color 200ms cubic-bezier(.2,.7,.3,1);
|
|
136
135
|
}
|
|
137
136
|
.pbtn:hover:not(:disabled), .settings-btn:hover:not(:disabled), .sessions-row__end:hover:not(:disabled),
|
|
138
|
-
.event-sound-preview:hover:not(:disabled)
|
|
139
|
-
.pbtn:disabled, .settings-btn:disabled, .sessions-row__end:disabled,
|
|
137
|
+
.event-sound-preview:hover:not(:disabled) { background: var(--glass-strong); color: var(--ink); text-decoration: none; }
|
|
138
|
+
.pbtn:disabled, .settings-btn:disabled, .sessions-row__end:disabled,
|
|
140
139
|
.pbtn[aria-disabled="true"], .settings-btn[aria-disabled="true"] { color: var(--ink-faint); background: var(--glass); cursor: default; }
|
|
141
140
|
.pbtn--quiet, .settings-btn--quiet, .sessions-row__end, .event-sound-preview { background: transparent; }
|
|
142
141
|
.pbtn--save,
|
|
143
|
-
.craft-save
|
|
144
|
-
.pbtn--save:hover:not(:disabled), .craft-save:hover:not(:disabled)
|
|
145
|
-
.craft-save:disabled, .pbtn--save:disabled
|
|
142
|
+
.craft-save { background: var(--accent); border-color: var(--accent); color: var(--accent-on); font-weight: 500; }
|
|
143
|
+
.pbtn--save:hover:not(:disabled), .craft-save:hover:not(:disabled) { background: var(--accent-lift); border-color: var(--accent-lift); color: var(--accent-on); }
|
|
144
|
+
.craft-save:disabled, .pbtn--save:disabled { background: var(--glass); border-color: var(--glass-edge); color: var(--ink-faint); }
|
|
146
145
|
/* the shell's `.craft-save` was a bordered box; it is the family's save button
|
|
147
146
|
now, so it carries the pill's own box model too */
|
|
148
147
|
button.craft-save { display: inline-flex; align-items: center; justify-content: center; min-height: 38px; min-width: 38px; padding: 0 15px; border-radius: var(--radius-pill); font: inherit; font-size: 14px; cursor: pointer; }
|
|
@@ -157,11 +157,6 @@ select.voices__select { min-width: 140px; }
|
|
|
157
157
|
.settings-btn--discord { background: #5865F2; border-color: #4853c4; color: #ffffff; }
|
|
158
158
|
.settings-btn--discord:hover:not(:disabled) { background: #4853c4; border-color: #4853c4; color: #ffffff; }
|
|
159
159
|
|
|
160
|
-
/* ---- dev box ------------------------------------------------------------- */
|
|
161
|
-
/* the box panel is the shell's (.setup__box, box-panel.js); inside a settings
|
|
162
|
-
panel it sits on the glass rather than a second card */
|
|
163
|
-
.settings-groups .setup__box { margin: var(--sp-sm) 0 0; background: var(--glass); border-color: var(--glass-edge); border-radius: var(--radius-sm); }
|
|
164
|
-
|
|
165
160
|
/* Specialities panel (task 1003855, ADR 0296). A speciality is a named bundle of
|
|
166
161
|
knowledge and terms under a craft; this styles the list, the train form and the
|
|
167
162
|
create form. Tokens only — no literal colours, so light/dark follow the page. */
|
|
@@ -195,20 +195,6 @@
|
|
|
195
195
|
|
|
196
196
|
<!-- ============ group: devbox ============ -->
|
|
197
197
|
|
|
198
|
-
<!-- DEV BOX — full box management (#807, ADR 0040). Request/wake, open
|
|
199
|
-
the online terminal, see SSH details, and close the box. Settings
|
|
200
|
-
shows BOTH the online terminal AND the SSH IP + command. The
|
|
201
|
-
OTBBoxPanel module (box-panel.js) renders + polls inside #box-mount. -->
|
|
202
|
-
<section class="scroll" id="box-scroll" aria-labelledby="box-h" data-group="devbox" hidden>
|
|
203
|
-
<h2 id="box-h" class="scroll__h">Your dev box</h2>
|
|
204
|
-
<p class="scroll__lede">
|
|
205
|
-
The hosted machine your work runs on. Open it in your browser (the
|
|
206
|
-
online terminal) or connect over SSH — whichever you prefer.
|
|
207
|
-
</p>
|
|
208
|
-
<div class="setup__box" id="box-mount"></div>
|
|
209
|
-
<p class="section-note">Actions apply at once. Closing stops and deletes the box; you can start a fresh one anytime.</p>
|
|
210
|
-
</section>
|
|
211
|
-
|
|
212
198
|
<!-- DEV BOX APP — the desktop switch (#904, ADR 0044). Static download
|
|
213
199
|
links; the /downloads/devbox/* redirects resolve to the current
|
|
214
200
|
release (config/devbox-app.json). -->
|
|
@@ -236,19 +222,6 @@
|
|
|
236
222
|
</p>
|
|
237
223
|
</section>
|
|
238
224
|
|
|
239
|
-
<!-- PAIRING — link out to the dedicated pair page (task 2172): keeps
|
|
240
|
-
the whole dev-box story reachable from this group. -->
|
|
241
|
-
<section class="scroll" id="pairing-scroll" aria-labelledby="pairing-h" data-group="devbox" hidden>
|
|
242
|
-
<h2 id="pairing-h" class="scroll__h">Pair Claude Desktop</h2>
|
|
243
|
-
<p class="scroll__lede">
|
|
244
|
-
Connect your Claude Desktop to your dev box with a one-time pairing
|
|
245
|
-
code — the guided flow lives on its own page.
|
|
246
|
-
</p>
|
|
247
|
-
<div class="settings-card">
|
|
248
|
-
<a class="settings-btn" href="/pair">Open the pairing page</a>
|
|
249
|
-
</div>
|
|
250
|
-
</section>
|
|
251
|
-
|
|
252
225
|
<!-- ============ group: preferences ============ -->
|
|
253
226
|
|
|
254
227
|
<!-- INTERACTION PROFILE — how replies are pitched for you (task 2010,
|
|
@@ -453,8 +426,6 @@
|
|
|
453
426
|
<!-- shared record overlay (#/idea|blocker/N) — every hall page carries it; this
|
|
454
427
|
page was the one gap (task 2172). -->
|
|
455
428
|
<script src="/builders/task-detail.js?v=2026-07-03-taskdetail"></script>
|
|
456
|
-
<!-- #807: shared dev-box panel — loaded before settings.js so OTBBoxPanel exists. -->
|
|
457
|
-
<script src="/builders/box-panel.js?v=2026-06-14-domutils"></script>
|
|
458
429
|
<script src="/builders/settings.js?v=2026-09-02-panel"></script>
|
|
459
430
|
<!-- task 1003341: the Active sessions panel. Its own file rather than more of
|
|
460
431
|
settings.js, which sits close to the 1500-line size ratchet. -->
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
//
|
|
7
7
|
// 1. VOICES — per-skill model picker (GET/PATCH /api/bongos/me/skill-prefs).
|
|
8
8
|
// 2. CRAFT — preferred disciplines (GET /api/bongos/me, PATCH /api/bongos/me/disciplines).
|
|
9
|
-
// 3. DEV BOX — full box management via the shared OTBBoxPanel (#807, ADR 0040):
|
|
10
|
-
// request/open the online terminal, SSH details, and close.
|
|
11
9
|
// 5. SOUNDS — per-sound on/off toggles (GET/PATCH /api/bongos/me/sound-prefs, #786).
|
|
12
10
|
//
|
|
13
11
|
// On a 401 it redirects into the web sign-in flow, like the other hall pages.
|
|
@@ -813,24 +811,6 @@
|
|
|
813
811
|
$('#display-name-scroll').hidden = false;
|
|
814
812
|
}
|
|
815
813
|
|
|
816
|
-
// ---- section 1b: DEV BOX (full management, #807 ADR 0040) ----------------
|
|
817
|
-
//
|
|
818
|
-
// Mounts the shared OTBBoxPanel (box-panel.js) with showSsh:true so a builder
|
|
819
|
-
// sees BOTH the online terminal and the SSH IP + command, and can request,
|
|
820
|
-
// open, or close their box. The module owns its own polling + state painting;
|
|
821
|
-
// we just hand it the mount element. Hidden if the module failed to load.
|
|
822
|
-
function setupBox() {
|
|
823
|
-
// R60 (task 1199): dev boxes are a feature module. On a vanilla instance the
|
|
824
|
-
// module is off — there is no box to manage, so the whole section stays
|
|
825
|
-
// hidden (its #box-scroll defaults to hidden in the markup).
|
|
826
|
-
if (!window.OTB.moduleOn('dev-box')) return;
|
|
827
|
-
const mount = $('#box-mount');
|
|
828
|
-
if (!mount || !window.OTBBoxPanel) return;
|
|
829
|
-
const panel = window.OTBBoxPanel.create({ api: API, showSsh: true, toast });
|
|
830
|
-
$('#box-scroll').hidden = false;
|
|
831
|
-
panel.mount(mount);
|
|
832
|
-
}
|
|
833
|
-
|
|
834
814
|
// ---- section 3: CONNECTIONS (Discord link/unlink, F7 ADR 0033) -----------
|
|
835
815
|
//
|
|
836
816
|
// The /me payload carries `discord: { configured, linked }`. The section is
|
|
@@ -1243,9 +1223,7 @@
|
|
|
1243
1223
|
'disciplines': 'craft-scroll',
|
|
1244
1224
|
'cli': 'cli-scroll',
|
|
1245
1225
|
'art-key': 'art-key',
|
|
1246
|
-
'dev-box': 'box-scroll',
|
|
1247
1226
|
'dev-box-app': 'boxapp-scroll',
|
|
1248
|
-
'pairing': 'pairing-scroll',
|
|
1249
1227
|
'interaction': 'interaction-scroll',
|
|
1250
1228
|
'wandering': 'wandering-scroll',
|
|
1251
1229
|
'rendering': 'render-scroll',
|
|
@@ -1358,14 +1336,11 @@
|
|
|
1358
1336
|
// DISPLAY NAME — the label beside your work (task 1669); seeded from /me.
|
|
1359
1337
|
setupDisplayName(builder);
|
|
1360
1338
|
|
|
1361
|
-
// DEV BOX —
|
|
1362
|
-
setupBox();
|
|
1363
|
-
// DEV BOX APP + PAIRING — revealed once we know the viewer is a real builder,
|
|
1339
|
+
// DEV BOX APP — revealed once we know the viewer is a real builder,
|
|
1364
1340
|
// and only where the dev-box module runs (the group's rail entry is gated
|
|
1365
1341
|
// the same way above — task 2172).
|
|
1366
1342
|
if (window.OTB.moduleOn('dev-box')) {
|
|
1367
1343
|
$('#boxapp-scroll').hidden = false;
|
|
1368
|
-
$('#pairing-scroll').hidden = false;
|
|
1369
1344
|
loadDevboxLatestVersion(); // #924: best-effort "latest version: X" courtesy line
|
|
1370
1345
|
}
|
|
1371
1346
|
// CONNECTIONS — Discord (hidden unless the server has Discord configured).
|
|
@@ -314,7 +314,6 @@
|
|
|
314
314
|
// Metic+ oversight could not honestly hold it. Everything below IS a rank
|
|
315
315
|
// surface, so this group's gate and audience are unchanged.
|
|
316
316
|
{ id: 'watch', label: 'Watch', icon: 'admin', href: '/watch', gate: 'government' },
|
|
317
|
-
{ id: 'harbor', label: 'Harbor', icon: 'admin', href: '/harbor', gate: 'government', module: 'dev-box' },
|
|
318
317
|
{ id: 'gate', label: 'Gate', icon: 'admin', href: '/gate', gate: 'government' },
|
|
319
318
|
{ id: 'sessions', label: 'Sessions', icon: 'admin', href: '/sessions', gate: 'government' },
|
|
320
319
|
// The project's own fundamentals (task 1003280, goal 1000072). Mirrors the
|
|
@@ -2421,50 +2421,6 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
|
|
|
2421
2421
|
}
|
|
2422
2422
|
.setup__btn:hover:not(:disabled) { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; text-decoration: none; }
|
|
2423
2423
|
.setup__btn:disabled, .setup__btn--open[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
|
|
2424
|
-
.setup__btn--box { background: var(--surface); border-color: var(--border-strong); color: var(--ink); }
|
|
2425
|
-
.setup__btn--box:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
|
|
2426
|
-
.setup__btn--danger { background: var(--surface); border-color: color-mix(in srgb, var(--danger) 45%, transparent); color: var(--danger); }
|
|
2427
|
-
.setup__btn--danger:hover:not(:disabled) { background: var(--danger-weak); }
|
|
2428
|
-
|
|
2429
|
-
.setup__box { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px 14px; margin: 10px 0; background: var(--surface-2); }
|
|
2430
|
-
.setup__box-btns { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
|
|
2431
|
-
.setup__box-msg { font-size: 13px; margin: 6px 0; }
|
|
2432
|
-
.setup__box-msg--ok { color: var(--ok); }
|
|
2433
|
-
.setup__box-msg--warn { color: var(--warn); }
|
|
2434
|
-
.setup__box-msg--err { color: var(--danger); }
|
|
2435
|
-
.setup__box-out {
|
|
2436
|
-
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
2437
|
-
font-size: 12px;
|
|
2438
|
-
background: var(--surface);
|
|
2439
|
-
border: 1px solid var(--border);
|
|
2440
|
-
border-radius: var(--radius-sm);
|
|
2441
|
-
padding: 8px 10px;
|
|
2442
|
-
max-height: 180px;
|
|
2443
|
-
overflow: auto;
|
|
2444
|
-
}
|
|
2445
|
-
.setup__box-close { margin-left: auto; }
|
|
2446
|
-
.setup__box-close-hint { font-size: 12px; color: var(--ink-faint); }
|
|
2447
|
-
.setup__cred-row { display: flex; align-items: center; gap: 8px; margin: 4px 0; font-size: 13px; flex-wrap: wrap; }
|
|
2448
|
-
.setup__cred-k { color: var(--ink-faint); min-width: 90px; }
|
|
2449
|
-
.setup__cred-v {
|
|
2450
|
-
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
2451
|
-
font-size: 12px;
|
|
2452
|
-
background: var(--surface-2);
|
|
2453
|
-
border: 1px solid var(--border);
|
|
2454
|
-
border-radius: 4px;
|
|
2455
|
-
padding: 2px 8px;
|
|
2456
|
-
}
|
|
2457
|
-
.setup__copy {
|
|
2458
|
-
border: 1px solid var(--border-strong);
|
|
2459
|
-
background: var(--surface);
|
|
2460
|
-
color: var(--ink-soft);
|
|
2461
|
-
border-radius: var(--radius-sm);
|
|
2462
|
-
font-size: 12px;
|
|
2463
|
-
padding: 3px 10px;
|
|
2464
|
-
cursor: pointer;
|
|
2465
|
-
}
|
|
2466
|
-
.setup__copy:hover { background: var(--surface-2); }
|
|
2467
|
-
.setup__copy--copied { background: var(--ok-weak); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
|
|
2468
2424
|
.setup__getcode { margin: 10px 0; }
|
|
2469
2425
|
/* A <summary> is a control, so it owes the 24px floor like any other; it
|
|
2470
2426
|
measured 20px tall (task 1003304). The height is bought with padding rather
|
|
@@ -536,8 +536,12 @@
|
|
|
536
536
|
// word is the thing the round's stat-tile reference exists to fix.
|
|
537
537
|
const meta = [];
|
|
538
538
|
if (t.version_id) meta.push(`<b>${escapeHtml(t.version_id)}</b>`);
|
|
539
|
-
|
|
540
|
-
|
|
539
|
+
// Neither axis says the word its column defaults to (task 1004038). `if
|
|
540
|
+
// (t.kind)` was never a guard for it: 'unclassified' is a truthy string, so
|
|
541
|
+
// the run read it out loud. The role line below asked the same question with
|
|
542
|
+
// a literal — it is right, but a copy of roleIsUnset() is free to drift.
|
|
543
|
+
if (!window.OTB.kindIsUnset(t.kind)) meta.push(escapeHtml(t.kind));
|
|
544
|
+
if (!window.OTB.roleIsUnset(t.discipline)) meta.push(escapeHtml(t.discipline));
|
|
541
545
|
// rankText() answers "any rank" for an open task, which read as
|
|
542
546
|
// "min rank any rank" once the label was prefixed. An open floor is not a
|
|
543
547
|
// minimum, so it is said as the absence of one.
|
|
@@ -89,13 +89,6 @@
|
|
|
89
89
|
<!-- ============ tab: Operations ============ -->
|
|
90
90
|
<div id="pane-operations" role="tabpanel" aria-labelledby="tab-operations" hidden>
|
|
91
91
|
|
|
92
|
-
<!-- 5. BOX COSTS (#602) — per-builder dev-box cost ledger + totals. -->
|
|
93
|
-
<section class="scroll" id="box-costs-scroll" aria-labelledby="box-costs-h" hidden>
|
|
94
|
-
<h2 id="box-costs-h" class="scroll__h">Dev-box costs</h2>
|
|
95
|
-
<p class="scroll__lede">What each builder's dev box has cost — spin-up, compute, and storage. Tracked for oversight; not charged in the early stage.</p>
|
|
96
|
-
<div id="box-costs-body"><span class="kit-skel"></span></div>
|
|
97
|
-
</section>
|
|
98
|
-
|
|
99
92
|
<!-- 6. SESSIONS — the tally, and the five most recent sessions the page
|
|
100
93
|
always fetched and used to throw away (task 1003469). -->
|
|
101
94
|
<section class="scroll" id="sessions-scroll" aria-labelledby="sessions-h" hidden>
|
|
@@ -897,41 +897,6 @@
|
|
|
897
897
|
});
|
|
898
898
|
}
|
|
899
899
|
|
|
900
|
-
// ---- Box costs (#602): per-builder container-cost totals + recent ledger ----
|
|
901
|
-
function renderBoxCosts(data, target) {
|
|
902
|
-
const totals = Array.isArray(data.totals_by_builder) ? data.totals_by_builder : [];
|
|
903
|
-
const recent = Array.isArray(data.ledger) ? data.ledger : [];
|
|
904
|
-
const usd = (n) => `$${(Number(n) || 0).toFixed(2)}`;
|
|
905
|
-
target.innerHTML = '';
|
|
906
|
-
if (!totals.length) {
|
|
907
|
-
target.innerHTML = emptyStateHtml('No dev-box costs accrued yet.');
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
ledger(group(target, 'Totals by builder', totals.length), {
|
|
911
|
-
columns: ['Builder', { label: 'Total', class: 'num' }],
|
|
912
|
-
rowHtml: (tb) => `<tr><td>${escapeHtml(tb.builder_login || ('#' + (tb.builder_id ?? '?')))}</td><td class="num">${usd(tb.total_usd)}</td></tr>`,
|
|
913
|
-
}).render(totals);
|
|
914
|
-
ledger(group(target, 'Recent ledger', recent.length), {
|
|
915
|
-
columns: ['When', 'Builder', 'Kind', { label: 'Amount', class: 'num' }, 'Detail'],
|
|
916
|
-
pager: makePager('watch-boxcosts', 'otb.watch.boxCostsPerPage'),
|
|
917
|
-
emptyMsg: 'No ledger rows yet.',
|
|
918
|
-
rowHtml: (r) => `<tr><td>${escapeHtml(String(r.recorded_at || '').slice(0, 16).replace('T', ' '))}</td>` +
|
|
919
|
-
`<td>${escapeHtml(r.builder_login || ('#' + (r.builder_id ?? '?')))}</td>` +
|
|
920
|
-
`<td><span class="ov-mono">${escapeHtml((r.source || '').replace('box-', ''))}</span></td>` +
|
|
921
|
-
`<td class="num">${usd(r.amount_usd)}</td>` +
|
|
922
|
-
`<td>${escapeHtml(r.description || '')}</td></tr>`,
|
|
923
|
-
}).render(recent);
|
|
924
|
-
target.insertAdjacentHTML('beforeend', foot('Container cost is tracked for oversight — not charged in the early stage.'));
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
function loadBoxCosts() {
|
|
928
|
-
return section($('#box-costs-body'), () => fetchJson('/boxes/cost-ledger?limit=100'), renderBoxCosts, {
|
|
929
|
-
sealedMsg: 'The cost ledger is not visible at your rank.',
|
|
930
|
-
errMsg: 'Could not load the dev-box cost ledger.',
|
|
931
|
-
name: 'box costs',
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
|
|
935
900
|
// =========================================================================
|
|
936
901
|
// 4. MARKS — reviews by builder (per-builder grade breakdown)
|
|
937
902
|
// NOTE: built in parallel — code defensively (404 / [] / missing fields).
|
|
@@ -1316,7 +1281,7 @@
|
|
|
1316
1281
|
|
|
1317
1282
|
function revealSections() {
|
|
1318
1283
|
[
|
|
1319
|
-
'watch-attention', 'watch-tabs', 'gate-scroll', 'watch-scroll', 'roster-scroll',
|
|
1284
|
+
'watch-attention', 'watch-tabs', 'gate-scroll', 'watch-scroll', 'roster-scroll',
|
|
1320
1285
|
'marks-scroll', 'mason-marks-scroll', 'surveyor-scroll', 'ledger-scroll', 'sessions-scroll',
|
|
1321
1286
|
].forEach((id) => {
|
|
1322
1287
|
const el = document.getElementById(id);
|
|
@@ -1376,7 +1341,6 @@
|
|
|
1376
1341
|
loadOverrides();
|
|
1377
1342
|
loadAudit();
|
|
1378
1343
|
loadRoster();
|
|
1379
|
-
loadBoxCosts();
|
|
1380
1344
|
loadMarks();
|
|
1381
1345
|
loadMasonMarks();
|
|
1382
1346
|
loadSurveyor();
|