@bongos/core 1.19.386 → 1.19.388
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 +138 -53
- package/config/branding.neutral.json +19 -19
- package/config/design-tokens.neutral.json +31 -36
- package/docs/adr/0196-chrome-world-token-contract-and-the-landing-sheets.md +31 -0
- package/docs/adr/README.md +1 -0
- package/docs/branding-contract.md +1 -1
- package/docs/copy-inventory.md +156 -133
- package/docs/copy-registry.json +537 -286
- package/docs/file-map.md +14 -0
- package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
- package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
- package/modules/dev-box/app/assets/tray/win-off.png +0 -0
- package/modules/dev-box/app/assets/tray/win-on.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
- package/modules/dev-box/app/build-resources/icon.png +0 -0
- package/modules/dev-box/app/renderer/index.html +1 -1
- package/modules/dev-box/app/renderer/styles.css +3 -1
- package/modules/dev-box/app/renderer/theme.generated.css +13 -13
- package/modules/dev-box/app/scripts/gen-brand.js +13 -13
- package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +3 -3
- package/modules/dev-box/app/scripts/gen-icons.js +3 -3
- package/modules/dev-box/app/src/brand.generated.json +1 -1
- package/modules/hall-ui/public/government.css +70 -0
- package/modules/hall-ui/public/government.html +9 -2
- package/modules/hall-ui/public/government.js +175 -32
- package/modules/provisioning/routes/provisioning.js +4 -4
- package/modules/status-ui/public/explore.html +12 -6
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +82 -64
- package/public-landing/assets/world/og-card.jpg +0 -0
- package/public-landing/assets/world/r2-bongos-chrome-a-cut.webp +0 -0
- package/public-landing/assets/world/r2-bongos-chrome-a-cut.webp.json +12 -0
- package/public-landing/assets/world/r2-bongos-chrome-b.jpg +0 -0
- package/public-landing/assets/world/r2-bongos-chrome-b.jpg.json +12 -0
- package/public-landing/assets/world/r2-chrome-blob-one-cut.webp +0 -0
- package/public-landing/assets/world/r2-chrome-blob-one-cut.webp.json +13 -0
- package/public-landing/assets/world/r2-chrome-blob-one.jpg +0 -0
- package/public-landing/assets/world/r2-chrome-blob-one.jpg.json +12 -0
- package/public-landing/assets/world/r2-chrome-blobs-set-cut.webp +0 -0
- package/public-landing/assets/world/r2-chrome-blobs-set-cut.webp.json +13 -0
- package/public-landing/assets/world/r2-chrome-blobs-set.jpg +0 -0
- package/public-landing/assets/world/r2-chrome-blobs-set.jpg.json +12 -0
- package/public-landing/assets/world.css +241 -0
- package/public-landing/contact.html +1 -1
- package/public-landing/index.html +1139 -580
- package/public-landing/privacy.html +1 -1
- package/public-landing/projects.html +2 -2
- package/public-landing/terms.html +1 -1
- package/src/bongos/platform-visibility-gate.js +8 -7
- package/src/bongos/stealth-gate.js +9 -8
- package/src/module-api.js +5 -1
- package/src/ui/adapters/claude-design/index.js +2 -2
- package/tests/cloud_bongos_pack.mjs +22 -18
- package/tests/cosmos_token_contrast.mjs +23 -8
- package/tests/government_board_room_copy.mjs +131 -0
- package/tests/landing_legal_pages.mjs +8 -5
- package/tests/landing_page.mjs +295 -166
- package/tests/platform_boot.mjs +3 -1
- package/tests/projects_hub.mjs +9 -5
- package/tests/projects_hub_pre_uat.mjs +3 -1
- package/tests/world_tokens.mjs +351 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ADR 0196 — The chrome world becomes the token contract; the landing gets its own world sheet beside the hub's
|
|
2
|
+
|
|
3
|
+
- **Status:** accepted
|
|
4
|
+
- **Date:** 2026-08-27
|
|
5
|
+
- **Task:** [task 1003298](https://cloudbongos.com/builders#/task/1003298) (goal 1000080 — Apex UI pass 2; criterion `apex-landing-built-design-recorded`)
|
|
6
|
+
- **Relates to:** ADR 0062 §3/§7 (the branding contract; the core ↔ host split), ADR 0064 (the retired sunrise look), ADR 0081 (the tool-agnostic design layer: `config/design-tokens.*`), ADR 0095 (findability), task 1003296 (the world pick), task 1003297 (the composition pick and the light-mode decision), `docs/design/apex-pass-2-direction.md`, `docs/design/<redacted>.md`, `DESIGN.md` (written from the build this task lands)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
The owner chose a new visual world for every apex surface (chrome-blobs, composition A; task 1003296) and, for the landing, the composition v3 "the template's page" with light mode rebuilt to the dark standard (task 1003297). The build has to make that world *real* in code that a host instance can still re-theme: every served page gets the pack's `theme.ui` spliced into `<head>` as a plain `:root` after its stylesheet (ADR 0062 §3), so the thirteen colours and two font stacks in `config/branding.neutral.json` are the only colour source the platform may rely on. The hub (`/projects`), the legal pages, the hall and the status pages all read the same pack; the hub's component sheet `public-landing/assets/cosmos.css` was tuned to the sunrise palette and carries its own ~60 derived tokens and the gate's locked space palette.
|
|
11
|
+
|
|
12
|
+
Three facts shaped the decision:
|
|
13
|
+
|
|
14
|
+
1. **The pack is one-mode.** `themeMarkup()` emits light values; dark exists only where a stylesheet writes `:root[data-mode="dark"]` and its `prefers-color-scheme` twin at (0,2,0). "Dark-first" is therefore a design stance, not a cascade order: the bare `:root` of every sheet must equal the pack's light values (the drift tests), and dark is the override.
|
|
15
|
+
2. **The world's derived vocabulary collides with the hub's.** The mock token layer (`docs/design/mocks/world/chrome-blobs/_tokens.css`) defines `--line` as a 1px width; cosmos.css defines `--line` as a hairline colour. The world's `--ok/--warn/--err` are warm accent states; the hub's are the fixed green/amber/red status vocabulary its chips depend on. Merging the two tiers into one `:root` would have silently repainted the hub's status chips and broken the strip's state marks.
|
|
16
|
+
3. **Chromium resolves `url()` inside a custom property against the document**, not the declaring stylesheet (verified in task 1003297 with a probe page). A token layer that names plates must use root-absolute paths or every route but one 404s.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
1. **The neutral pack moves to the chrome world.** `config/branding.neutral.json` `theme.ui` now carries the world's light values (`--bg #edecee`, `--bg-card #fbfafc`, `--ink #17181a`, `--accent #fb9569`, Manrope for display and body, JetBrains Mono via the same fonts link) and `config/design-tokens.neutral.json` mirrors it key for key. `--accent-deep` is **#a3481a**, not the mock's #d96a35: the mock never painted text with it, but the hub and the gate pages do, and #a3481a is the lightest burnt orange that clears 4.5:1 on all three light grounds (5.77:1 card, 5.10:1 page, 4.61:1 deep). The mock's rgba hairlines are flattened onto the page ground (`--rule #c6c6c8`, `--rule-soft #dcdbdd`) so every consumer that does hex maths still works.
|
|
21
|
+
2. **`backdrop` is `var(--bg)`.** The pack's `theme.ui.backdrop` becomes a `body{background:…}` rule that outranks every sheet in both modes; a literal there pinned the light ground under the dark page. `var(--bg)` follows the mode because the dark blocks win the token. The `.sky` layer the old landing kept to paint over that rule is gone.
|
|
22
|
+
3. **The landing gets its own world sheet, `public-landing/assets/world.css`, and `cosmos.css` stays the hub's until the hub round.** `world.css` is the world's token layer: the contract tier (equal to the pack), the derived tier for both modes (the void, glass, accent behaviours, state, ramps, halos, radii, label faces), the plate tokens as root-absolute `/assets/world/…` pairs (black plate + alpha cutout), and the reduced-motion kill switch. It carries no page composition: layout switches live on the page's own `body` rules, where every dark override is written twice. `cosmos.css` keeps the hub's components; its contract tier is synced to the pack, its dark tier moves to the world's black ground, and its derived tier is retuned so its contrast pairs clear AA on the salmon accent (dark ink on the accent fill, never white). A4 (task 1003299) rebuilds the hub on the world sheet; H1/S1 build the hall and status against `DESIGN.md` + the pack, each deriving its own tier the way `world.css` does.
|
|
23
|
+
4. **Plates ship in `public-landing/assets/world/` with provenance embedded.** The three black plates are verbatim JPEG copies (the prompt in the COM segment), the three cutouts are WebP with alpha at 1600px (85–170 KB against 1.1–2.4 MB PNG), each with a `<file>.json` sidecar naming the source render, the encoding and the mode it serves; `embed-prompt.mjs --scan` finds none missing. Plate URLs inside CSS custom properties are not covered by the server's `?v=` content stamp (it stamps `href`/`src` attributes), so a changed plate at the same path can be cached at the edge for four hours; plates change rarely and get a new filename when they do.
|
|
24
|
+
5. **Live figures are baked inside apex-only sentinels and refreshed at render time.** The hero callouts, the ledger line and rows, and the featured orbs carry real values from the public feeds (dated in the page's head comment) as the no-JS state, wrapped in `<!--apex-only:start-->…<!--apex-only:end-->` so a child instance renders an empty figure rather than the platform's number until its own feed answers; the script then fills every instance live from `/public/progress`, `/public/cost-summary`, `/public/leaderboard`, `/public/recent-shipped` and `/projects/featured`, building DOM with `createElement`/`textContent` only, keeping the baked state on any failure. Definitions are fixed here so the numbers stay honest: *tasks shipped* is the sum of `shipped_count` over every version row; *credits of value* is `total_value_credits`; *builders holding credits* is the leaderboard count with `total_credits > 0` (the world round's "6" was the ninety-day active count, a different thing); the ledger line is the first `building` version. Live titles are quoted data: em and en dashes are normalised to a comma at render time and a trailing parenthetical is dropped, so the taste ban holds without editing the ledger.
|
|
25
|
+
|
|
26
|
+
## Consequences
|
|
27
|
+
|
|
28
|
+
- Every surface that reads the pack re-themes at once: the hub, the legal pages, the hall and the status pages render on the pale grey / black grounds with Manrope before their own rounds restyle their components. That is the intended order — the token contract lands first, the surfaces follow — and the fallback-literal sites the tests pin (the claude-design adapter, the status explore page, the provisioning onboarding pages, the dev-box brand artifacts and tray icons, the two gate pages) are updated in this task so the suite stays green and no page keeps a private palette.
|
|
29
|
+
- Two sheets share one contract. The rule for any new surface: a bare `:root` equal to the pack, a derived tier of its own, dark written twice at (0,2,0), no literal accent in a dark block, no `:root` in a page. `DESIGN.md` records the world's derived recipes so a surface's derived tier is a port, not an invention.
|
|
30
|
+
- The landing no longer links `cosmos.css`; `tests/landing_page.mjs` guards `world.css` + `index.html` (the apex conditional, the stamped head, the cascade, portability, the kill switch, the live hooks) and `tests/world_tokens.mjs` measures the world sheet's pairs from the real CSS the way `tests/cosmos_token_contrast.mjs` measures the hub's.
|
|
31
|
+
- Rejected: folding the world tier into `cosmos.css` (the collisions above); keeping the pack on the sunrise and letting the landing carry its own palette (the fifteen-token rule would be dead and no host could re-theme the front door); shipping the cutouts as PNG (four to six megabytes for a first paint); a script-built ledger with no baked state (a scriptless visitor or a crawler would see an empty page); `#d96a35` as `--accent-deep` (3.3:1 on the card everywhere the hub paints text with it).
|
package/docs/adr/README.md
CHANGED
|
@@ -283,5 +283,6 @@ This keeps the decision history honest and traceable.
|
|
|
283
283
|
| 0193 | [**Pause task-scoped box slices: a box serves its rank scope (the full repo for Metic+)** ([task 1003285](https://cloudbongos.com/builders#/task/1003285), owner decision from the 2026-08-25 dev-box efficiency review). Pauses, does not repeal, ADR 0148 / goal 1000051: `routes/box.js` skips the lifecycle-port `scopeKeys` resolution unless `BOX_TASK_SCOPE=on`, so `decideSourceAccess` takes its documented rank fallback — full repo for Metic+, starter surface below. WHY: the slice was defense-in-depth git cannot hard-enforce (ADR 0031 §6's honest limit) while its costs were real on the live fleet — sessions on a box that cannot see a module (or its nested CLAUDE.md) misdiagnose themselves as stuck, the scope machinery kept failing in the field (task 1002729's base-slice collapse), and every live box user is Metic+ anyway, so the slice narrowed trusted builders while newcomers were already gated by rank. UNCHANGED: live-rank allow/deny per request (ADR 0016), the provision floor and demotion clawback, the read-only per-request credential (ADR 0055 — push still 403s, re-verified on hardware in task 1003253), and sub-Metic starter boxes. `GET /box/scope` now reports `task_scoping_paused` so the hall/app can say why `task_scope` is false; the app task-picker's "scoped to `<modules>` and nothing else" copy overstates while paused (cosmetic). Revert = set the env flag; make-permanent = delete the resolution + a follow-up ADR.](<redacted>.md) | dev-box |
|
|
284
284
|
| 0194 | [**A project's membership door is one decision, answered the same way everywhere a stranger meets it** ([task 1003044](https://cloudbongos.com/builders#/task/1003044), goal 1000058). The owner's 2026-08-16 joinability setting — open / apply / invite_only — was stored (1003040), pushed (1003139/1003140) and resolved into `branding().project.joinability`, enforced by nothing. Decision: ONE reader, `joinabilityMode()` in `auth-admission.js`, and `openEnrollmentEnabled()` becomes `mode === 'open'`, so the four sign-in call sites, `webAdmissionStatus` and the manifest's `admission.policy` follow untouched (SR-19: one gate, no drift). The legacy `OPEN_XENOS_ENROLLMENT` flag still opens an APPLY project — a self-hosted instance that set it keeps its door across the upgrade — but never reopens an explicit invite_only; an unreadable pack or a value this core cannot read fails CLOSED (invite_only), the ADR 0192 rule. The public `POST /access-requests` answers the door FIRST — before validation, before any lookup — `403 invite_only` / `409 open_enrollment` with plain sentences: no query, nothing revealed about who exists, and DB-free enough for the real booted app to prove. An Archon's invite is the row the gate already reads: `POST /access-requests/invite` writes `access_requests` at 'invited' (resolving a pending one in place), so sign-in consults nothing new — surfaced as "Invite by GitHub username" on the Watch page. The door is SAID wherever a stranger meets it, in the project's words: the hall landing renders one door per mode from the injected pack, the web 403 names the invite-only door and the way in, the CLI stops instead of filing, the hub's join relay names the door in the hub's own words (a project is trusted to build, not to write prose into the platform's UI) instead of painting a refusal as "requested" or "unreachable". `admission.policy` stays binary (pinned; agrees for free); `joinabilityMode` joins the doorway — a human MINOR by ADR 0161 §2, which the publish lane's LIVE test refused (HEAD's version must be a CI carrier's), so it rides the next CI patch and the contradiction is filed as an idea. The hub's `#mJoinability` clones `#mVisibility` rather than a factory — a third setting is where a factory pays. Rejected: folding the flag into `branding()` (memoized vs per-call; the manifest must stay the pushed value); a 200 for the open door (an older CLI would wait thirty minutes for an approval); re-deriving the mode inside the module; a second invite table.](<redacted>.md) | instance / project joinability |
|
|
285
285
|
| 0195 | [**ADR numbers are checked like migration numbers, and the twenty existing collisions are grandfathered by name** ([task 1003164](https://cloudbongos.com/builders#/task/1003164)). Two ADRs could share a number and nothing flagged it — git sees no path collision, the index auto-merges into two rows, and every gate passes; it was found by a human reading `ls docs/adr/`, after a task note had already cited a number the collision made point at an unrelated document. Migrations had this guard already (`stemCollisions()` hard-fails CI, because a re-used migration number silently skips a migration); ADRs had only a best-effort allocator at claim time and nothing afterwards. `scripts/gds/adr-namespace.js` is the sibling module, wired into fitness as Check 31 and so into the required `unit` gate. Building it found twenty live collisions, not one, plus fourteen index defects of the same merge class — two ADRs listed twice and twelve with no row at all, ten of them the second file of a colliding pair, which is how a collision hides. The twenty pairs are grandfathered by EXACT FILENAME rather than renumbered: renumbering breaks every citation to them, which is the harm the check exists to prevent, and set-equality keeps the exemption as narrow as the history that earned it — a third file on a legacy number, or a rename of either half, still fails, and the list may only shrink. The index half is keyed on LINK TARGET, not number (a number rule cannot express a grandfathered pair): every file has exactly one row, every row points at a file that exists. Row ordering warns and never blocks — ten legacy rows are out of order and no PR author caused that (the ADR 0189 split). Rejected: renumbering; grandfathering by number; a numeric cutoff like LEGACY_BARE_CORE_MAX (a new ADR takes a number above the max, so it would catch nothing); fixing it in the claim-time allocator (which already tries, against a stale tree — that is how the collision happened).](<redacted>.md) | docs / numbering discipline |
|
|
286
|
+
| 0196 | [**The chrome world becomes the token contract; the landing gets its own world sheet beside the hub's** ([task 1003298](https://cloudbongos.com/builders#/task/1003298), goal 1000080). The owner picked the chrome-blobs world (1003296) and the v3 composition with light rebuilt to the dark standard (1003297); this build makes it the platform's token contract. Decisions: (1) the neutral pack moves to the world's LIGHT values (pale grey paper, black ink, salmon accent, Manrope + JetBrains Mono) and design-tokens mirrors it; --accent-deep is #a3481a rather than the mock's #d96a35 because the hub and the gate pages paint TEXT with it and #a3481a is the lightest burnt orange clearing 4.5:1 on all three light grounds; the rgba hairlines are flattened to hex so hex-maths consumers survive. (2) theme.ui.backdrop becomes var(--bg): a literal there paints the light ground under the dark page in both modes, since the body rule outranks every sheet. (3) The landing gets its own world sheet public-landing/assets/world.css (contract tier = pack, derived tier both modes, root-absolute plate token PAIRS, the kill switch; NO composition switches) and cosmos.css stays the hub's component sheet until A4 — folding the two tiers would have collided (--line is a width in the world and a colour in the hub; the world's warm --ok/--warn/--err would repaint the hub's fixed green/amber/red chips). cosmos.css's dark tier moves to the world's black and its derived tier is retuned for the salmon accent (dark ink on the fill, never white). (4) Plates ship under public-landing/assets/world/ with provenance embedded: black plates verbatim JPEG, cutouts as WebP with alpha at 1600px (85–170 KB vs 1.1–2.4 MB PNG), sidecars; plate URLs in custom properties escape the ?v= stamp (edge cache 4h), accepted. (5) Live figures are BAKED inside apex-only sentinels (real, dated; a child renders empty until its own feed answers) and refreshed at render time from the five public feeds with fixed definitions: tasks shipped = the sum over every version row, builders = leaderboard entries holding credits, the ledger line = the first building version; live titles have em dashes normalised to a comma and a trailing parenthetical dropped. Every pack-reading fallback site (the claude-design adapter, the status explore page, provisioning onboarding, dev-box brand artifacts + tray icons, the two gate pages) is moved in the same task so no page keeps a private palette. Rejected: one merged token tier; a landing-private palette; PNG cutouts; a script-only ledger; #d96a35 as accent-deep.](<redacted>.md) | apex / design system |
|
|
286
287
|
|
|
287
288
|
> ⚠️ **Numbering collisions are now machine-enforced, not narrated.** Twenty numbers are shared by two ADRs each — assigned in parallel sessions before anything checked. The files keep their filenames (renumbering would break every existing citation, and a number once assigned is never reused), and this table disambiguates each pair as `NNNN-a` / `NNNN-b`. The authoritative list is `LEGACY_DUPLICATE_ADRS` in [`scripts/gds/adr-namespace.js`](../../scripts/gds/adr-namespace.js), frozen by exact filename: a **new** collision — or a third file joining a legacy number, or a rename of either half — hard-fails the `unit` CI gate, as does an index row that points at no file or an ADR with no row. The list may only shrink. This paragraph used to narrate the collisions one by one and had fallen eight behind reality; see [ADR 0195](<redacted>.md) for why the check exists and why the pairs are grandfathered rather than renumbered.
|
|
@@ -39,7 +39,7 @@ env override → instance config (config/branding.json) → neutral star
|
|
|
39
39
|
| `reward` | `{ marginPct, usdPeg, mode }` — the per-instance reward POLICY the economy module reads ([ADR 0054](adr/<redacted>.md) + ADR 0146, tasks 2009/1002270): the cost-plus margin percent (default `20`), the example-per-USD peg (default `1`), and `mode` — `"cost-plus-and-estimate"` (default; pay both the per-task author estimate AND the cost-plus session reward) or `"cost-plus-only"` (suppress the per-task estimate payout; the cost-plus session reward is the sole equity reward). A committed, code-reviewed change — not a live UI knob. Omit ⇒ code defaults (20% margin, 1:1 peg, pay both streams). |
|
|
40
40
|
| `models` | `{ main, subagentDefault, subagentRoutine }` — the per-instance subagent model-allocation DEFAULT the builder-settings module reads (task 2011): the tier for the main session, subagent-default work, and routine plumbing (tiers: `haiku`/`sonnet`/`opus`/`fable`). A per-builder override resolves over this. Omit ⇒ code defaults (`opus`/`opus`/`haiku`). |
|
|
41
41
|
| `tracks` | The configurable version-track set (replaces the hardcoded `product\|internal`). |
|
|
42
|
-
| `theme` | `{ palette, mode }` — palette file ref + theme mode. |
|
|
42
|
+
| `theme` | `{ palette, mode, ui }` — palette file ref + theme mode, plus `ui`, the WEB look `themeMarkup()` splices into every served page as a plain `:root` after the page's stylesheet: `colors` (the thirteen contract tokens — **light-mode values**; each stylesheet derives its own dark tier from them at `:root[data-mode="dark"]` + its `prefers-color-scheme` twin, which outrank the pack), `fonts` (`display`, `body`, `links`), `favicon`, and `backdrop` — a `body{background:…}` rule that outranks every sheet in **both** modes, so a dual-mode world sets it to `var(--bg)` (the neutral pack does since [task 1003298](https://cloudbongos.com/builders#/task/1003298), ADR 0196) rather than a literal. The neutral values are the chrome world's; `config/design-tokens.neutral.json` must mirror `colors` + `fonts` key for key (`tests/design_tokens_sync.mjs`), and the world's derived recipes are recorded in `DESIGN.md`. |
|
|
43
43
|
| `copy` | Instance copy keys (tagline, hallName, notFound, …). Full copy pack adoption = task [#1196](https://example.com/builders#/task/1196). |
|
|
44
44
|
| `landing.postLogin` | Where a successful web sign-in lands when it carried no explicit `?return=` / same-apex `Referer` (`src/bongos/routes/auth.js` `postLoginLanding`). **Portable default `/builders`** — the hall always exists. A platform-home instance points this at its OWN front door so a visitor who signs in from there returns there instead of being auto-redirected into the hall (cloudbongos.com → `/gate/`, the orbs). Validated through the same open-redirect allowlist as `?return=` (a misconfigured value falls back to `/builders`). Env-overridable: `<PREFIX>_POST_LOGIN_LANDING`. (task [#1002240](https://cloudbongos.com/builders#/task/1002240)) |
|
|
45
45
|
| `envPrefix` | Env-var namespace for overrides (`OTB`, `CLOUDBONGOS`, …). |
|