@bongos/core 1.19.413 → 1.19.414

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 CHANGED
@@ -2,22 +2,22 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.413",
6
- "core_contract": "1.19.413",
7
- "source_commit": "d76d3df7df9710c0f465ea480821e07f3618ba8a",
5
+ "core_version": "1.19.414",
6
+ "core_contract": "1.19.414",
7
+ "source_commit": "bf02216b3497eb7540e382dd5c4189a70fbb8cbc",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-29T15:10:10.945Z",
9
+ "built_at": "2026-08-29T15:34:28.312Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 354,
12
+ "docs_redacted": 355,
13
13
  "agent_docs_stubbed": 23,
14
14
  "functional_verbatim": 1669,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2046,
20
- "tree_sha256": "4e0995ef98f294d4511dc8574ae57a362cecd105b934a2a4f5831c3c1527fb0b",
19
+ "file_count": 2047,
20
+ "tree_sha256": "3ddb8a1e6c1997334734b740a0d435c770fc0bc811945f456e9ee7d61a046ed5",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -1519,10 +1519,15 @@
1519
1519
  "mode": "0000644",
1520
1520
  "sha256": "37c8ba1f75a3daac27d510e47f1dc392382084a726133db8d4e1db860031cca8"
1521
1521
  },
1522
+ {
1523
+ "path": "docs/adr/0204-the-apex-is-dark-only.md",
1524
+ "mode": "0000644",
1525
+ "sha256": "ac6a729436ff1e51414ccaf097b5e49c1360dd3bca1efd1ff73f38d4e5fca24d"
1526
+ },
1522
1527
  {
1523
1528
  "path": "docs/adr/README.md",
1524
1529
  "mode": "0000644",
1525
- "sha256": "3195734df44b011f7b9e312b02aa20cc0bcbf02763c19046c6501935b5befbff"
1530
+ "sha256": "32bf8baf396e3191e46525c1c5aeda326c0f1f7f6a83359f6fc5f5b6c8dda04c"
1526
1531
  },
1527
1532
  {
1528
1533
  "path": "docs/api-reference.md",
@@ -1557,12 +1562,12 @@
1557
1562
  {
1558
1563
  "path": "docs/copy-inventory.md",
1559
1564
  "mode": "0000644",
1560
- "sha256": "0935ecff01e0e750f9120947b227663f61510661c411cf96c99415c96fb99275"
1565
+ "sha256": "c462f7be788726d0bbe0186dcaa7288fa81b23550057ce9f579bc5b3d6096f44"
1561
1566
  },
1562
1567
  {
1563
1568
  "path": "docs/copy-registry.json",
1564
1569
  "mode": "0000644",
1565
- "sha256": "13447cec279cbe55c95346a67eeaacf9a349e472988cd40023015b042f9047cf"
1570
+ "sha256": "429fbb99f080c8bb80c8b8fc9539eb632dab1a4f6bb0534170667c76e055001d"
1566
1571
  },
1567
1572
  {
1568
1573
  "path": "docs/design/apex-pass-2-direction.md",
@@ -1587,7 +1592,7 @@
1587
1592
  {
1588
1593
  "path": "docs/design/landing-page-direction-v2.md",
1589
1594
  "mode": "0000644",
1590
- "sha256": "a4e5095ced6f287757e7b5c2d0fbef774e24f9bd658fd2e0b4c2b35f96eb728e"
1595
+ "sha256": "8602ef938cf855e675e454f4689b433f0f1dde4855337396d9f9a80b332dfda1"
1591
1596
  },
1592
1597
  {
1593
1598
  "path": "docs/design/landing-page-direction.md",
@@ -1807,7 +1812,7 @@
1807
1812
  {
1808
1813
  "path": "docs/design/projects-hub-direction-v2.md",
1809
1814
  "mode": "0000644",
1810
- "sha256": "b785d60798bd70e2a8f914ff93e94fc6f94723819abc9ccafff7ce96ef9921f6"
1815
+ "sha256": "30e3f767670141d142a3fc3608eb37745847d011c4659d61b20f67c10ef9e75a"
1811
1816
  },
1812
1817
  {
1813
1818
  "path": "docs/design/projects-hub-direction.md",
@@ -1867,7 +1872,7 @@
1867
1872
  {
1868
1873
  "path": "docs/module-api-changelog.md",
1869
1874
  "mode": "0000644",
1870
- "sha256": "ad1eb5201b24398e4609ff25d687069da2ba6f312dac48e1b287712cde0c8fe6"
1875
+ "sha256": "6eda8322f061bd29596304e3f51444eb69ba89d6e30da19b3a07fcf55fc900b2"
1871
1876
  },
1872
1877
  {
1873
1878
  "path": "docs/modules-contract.md",
@@ -2097,7 +2102,7 @@
2097
2102
  {
2098
2103
  "path": "docs/recipes/ui-look-before-you-ship.md",
2099
2104
  "mode": "0000644",
2100
- "sha256": "cdfc64513e7ae5f503dc25e63b4f79eb54ea44b1555102d86e21f2540e383d5d"
2105
+ "sha256": "1d29b5407a29c4a2fc7b2a7114cb6679f7104d6a0cf38b6a77606d529d0d8734"
2101
2106
  },
2102
2107
  {
2103
2108
  "path": "docs/recipes/upgrading-the-core.md",
@@ -5307,7 +5312,7 @@
5307
5312
  {
5308
5313
  "path": "modules/ui-design/kit/lib.js",
5309
5314
  "mode": "0000644",
5310
- "sha256": "b4aee13cd20243237ab8142f361aeb980f8f292409bf1c7fbe60c3b56426a44c"
5315
+ "sha256": "657c5ccebb7223aa7cf71f8ac25f18c6f28054931abbe6ac1ad1203733784f66"
5311
5316
  },
5312
5317
  {
5313
5318
  "path": "modules/ui-design/kit/png.js",
@@ -5322,7 +5327,7 @@
5322
5327
  {
5323
5328
  "path": "modules/ui-design/kit/render.js",
5324
5329
  "mode": "0000644",
5325
- "sha256": "15931b862ff62824b9916172d75df677bea186e1be23eefb99bbd4541932acfd"
5330
+ "sha256": "872bd51f1b221afa226e113c727ec1a428457e9a4621bcffe605642b7d7731e3"
5326
5331
  },
5327
5332
  {
5328
5333
  "path": "modules/ui-design/kit/serve.js",
@@ -5372,12 +5377,12 @@
5372
5377
  {
5373
5378
  "path": "package-lock.json",
5374
5379
  "mode": "0000644",
5375
- "sha256": "b4a7232c717443506a820d17ca00363221141d7494259f9f6b1a676a474c32ee"
5380
+ "sha256": "e7dc4f709fce538cf1f3eb7aa8e3ca2e68dbe66defc8f3f4ceb4bd2b95f76271"
5376
5381
  },
5377
5382
  {
5378
5383
  "path": "package.json",
5379
5384
  "mode": "0000644",
5380
- "sha256": "7c01dfae62c1038f19d70b09c7007f41abf4c18e17db201f2cd20011d65f938c"
5385
+ "sha256": "0e5ef83c47bd5bf9019c0110780af60d34cd5e01fb7d0a2f1a4354b2b371f93d"
5381
5386
  },
5382
5387
  {
5383
5388
  "path": "public-docs/index.html",
@@ -5617,7 +5622,7 @@
5617
5622
  {
5618
5623
  "path": "public-landing/assets/cosmos.css",
5619
5624
  "mode": "0000644",
5620
- "sha256": "9c7c390683c0cd15093f599392e600bf76ceb9a9e85791ccd95a0c79361963db"
5625
+ "sha256": "7e8e7a9bc2797d0bc6be5c2de46639307813047a60bd5904c60e1bded49bdef2"
5621
5626
  },
5622
5627
  {
5623
5628
  "path": "public-landing/assets/verro-medallion.png",
@@ -5702,12 +5707,12 @@
5702
5707
  {
5703
5708
  "path": "public-landing/contact.html",
5704
5709
  "mode": "0000644",
5705
- "sha256": "f8badb9283f0ef534b291f83daa1041bbcc9b20c11223ce080bffd1976a8b6be"
5710
+ "sha256": "22e81df702236494bff7f283cd25ecbca92df2ea485d995fbd66c0e924faff41"
5706
5711
  },
5707
5712
  {
5708
5713
  "path": "public-landing/index.html",
5709
5714
  "mode": "0000644",
5710
- "sha256": "45bb60cc5a5e2db12bc76426f3bf7990f9b18f64eb77603cd558f729e0252d71"
5715
+ "sha256": "9d1e904bdb89b929f29871c6c50cbdf9a33d73943b689d167ad26cb1201a01e2"
5711
5716
  },
5712
5717
  {
5713
5718
  "path": "public-landing/index.probes.json",
@@ -5717,32 +5722,32 @@
5717
5722
  {
5718
5723
  "path": "public-landing/index.states.json",
5719
5724
  "mode": "0000644",
5720
- "sha256": "8d5955085ab5059a15195d5c475262d114061d616dd9c82335a91a5992cc5602"
5725
+ "sha256": "9bc1178aa8f1afe770c6f1b97491c4f0afb8a301300f1e8818a33605f969a12e"
5721
5726
  },
5722
5727
  {
5723
5728
  "path": "public-landing/privacy.html",
5724
5729
  "mode": "0000644",
5725
- "sha256": "86723749e69f425aff0e2821fbef3572699f795c9de6a71cfd6f2549c6194ef0"
5730
+ "sha256": "5af37c9fd5be9c15ac195528764f87c2ade2b63a72a24fadfa87b83183769d28"
5726
5731
  },
5727
5732
  {
5728
5733
  "path": "public-landing/projects.html",
5729
5734
  "mode": "0000644",
5730
- "sha256": "e33a777d5d938892822c4dc6f66295ce0332c6336d25b67147d56519941240ee"
5735
+ "sha256": "5587b1f04ecf15c2b6a6a931bde87311414a995d83d18018f8a7162b423b7d24"
5731
5736
  },
5732
5737
  {
5733
5738
  "path": "public-landing/projects.probes.json",
5734
5739
  "mode": "0000644",
5735
- "sha256": "87dfa686a4c794e1dcdee05829c07a6849df91f1fbc6b0cd2ca9b3cdaa548235"
5740
+ "sha256": "f73eb875d55475f3380ee7356212262bfa053c86e072e6943cb77a8d3968af42"
5736
5741
  },
5737
5742
  {
5738
5743
  "path": "public-landing/projects.states.json",
5739
5744
  "mode": "0000644",
5740
- "sha256": "effa79569e3ef5ddb6fbff14d3121c077521c4b9599d19d253cdca6ef8965257"
5745
+ "sha256": "54d54a1fab92aa72ab8c09e9643d0e42524001d54c06d9d996f20958f6e3fa02"
5741
5746
  },
5742
5747
  {
5743
5748
  "path": "public-landing/terms.html",
5744
5749
  "mode": "0000644",
5745
- "sha256": "f52bde60845b4b9f728bfaee9fb88a8d921c5b56efd1807fef54ffa4d9c63351"
5750
+ "sha256": "06e12ecafb6dfa09cf7c1b8415fa67a78486dde334fd72bb6f71f5f474301444"
5746
5751
  },
5747
5752
  {
5748
5753
  "path": "public-landing/world/assets/clouds/cloud-island-large.png",
@@ -7012,7 +7017,7 @@
7012
7017
  {
7013
7018
  "path": "scripts/gds/worktree.js",
7014
7019
  "mode": "0000644",
7015
- "sha256": "74fc8349287498ede068156f904aaef3f7dbeafce2b40942dd5a8a2a0208564a"
7020
+ "sha256": "56549d4c288f55699ceb1fea10f4f65756a9114b4628b3f2b6c44fed0ec6ab26"
7016
7021
  },
7017
7022
  {
7018
7023
  "path": "scripts/hall-preview/README.md",
@@ -7392,7 +7397,7 @@
7392
7397
  {
7393
7398
  "path": "src/module-api.js",
7394
7399
  "mode": "0000644",
7395
- "sha256": "bf76bacb85922bac8e5c23a51a50535143cd7c6e2fbebad35cabd21913f43881"
7400
+ "sha256": "46d6abde6c291f8fa9168dfbe98b2dabfcd7c04dea6901a2df4fa343dc8764de"
7396
7401
  },
7397
7402
  {
7398
7403
  "path": "src/module-loader/catalog.js",
@@ -8997,12 +9002,12 @@
8997
9002
  {
8998
9003
  "path": "tests/landing_legal_pages.mjs",
8999
9004
  "mode": "0000644",
9000
- "sha256": "1005d6ea575e1fe71e41f77d227dd65ea69d7d0a6d3d8c787aee3c81154d2dab"
9005
+ "sha256": "dcf62524d2f4d8b3fdb019718b1fd8262618844aeae4504bbcbe153fd643fd17"
9001
9006
  },
9002
9007
  {
9003
9008
  "path": "tests/landing_page.mjs",
9004
9009
  "mode": "0000644",
9005
- "sha256": "5ef9a789374abe826534ecc5ea0c71445a3fceef147ce1b910310f23f4b541cb"
9010
+ "sha256": "cfdd0fa602c05c5ccc97cad3786a39f5941861597c947781dc23b2b7af12b137"
9006
9011
  },
9007
9012
  {
9008
9013
  "path": "tests/lib_sh_resolution.mjs",
@@ -9412,12 +9417,12 @@
9412
9417
  {
9413
9418
  "path": "tests/projects_hub.mjs",
9414
9419
  "mode": "0000644",
9415
- "sha256": "a60ccd5e60f85de08178ba17cf96652d49a9ceacfdde79426dc1711cfead9906"
9420
+ "sha256": "5da44f27ff5f930077237722957eabe02f5965602a8fed0927e0311f278273d0"
9416
9421
  },
9417
9422
  {
9418
9423
  "path": "tests/projects_hub_pre_uat.mjs",
9419
9424
  "mode": "0000644",
9420
- "sha256": "b99f0b272d40f655726597ca14546fda9799130522cbae70ce663094d8bd6efd"
9425
+ "sha256": "9cf9882d54011ea2284cb709c02abd2228d6a073b207e255b8958e0ca54794ae"
9421
9426
  },
9422
9427
  {
9423
9428
  "path": "tests/promote_goal_id.mjs",
@@ -10162,7 +10167,7 @@
10162
10167
  {
10163
10168
  "path": "tests/ui_design_kit.mjs",
10164
10169
  "mode": "0000644",
10165
- "sha256": "2e841f08e05a002ca38195f66fbe14743c93af4bc0f79becf361267dc7311fc6"
10170
+ "sha256": "25b4f754abb89f4a01237e81199dbcca824045563a2b6dbadca234227ff8ef3c"
10166
10171
  },
10167
10172
  {
10168
10173
  "path": "tests/ui_design_skills.mjs",
@@ -0,0 +1,36 @@
1
+ # 0204 — The apex is dark only; light is the builders' hall's
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-08-29
5
+ - **Deciders:** the owner (Archon), on the planets review of 2026-08-28: "only black or only white is a bit bland, frankly I am leaning towards only dark mode for this page and keep the dark/light mode to be solely for the builder hall. That way we could focus in on that style. This would also mean we could invest into a cool space themed backdrop for the blobs." Confirmed the same day as the WHOLE apex (landing, hub, legal pages), not the map alone. Claude implemented.
6
+ - **Task:** task 1003336 (goal 1000080 — Apex UI pass 2)
7
+ - **Supersedes in part:** [ADR 0196](<redacted>.md) — its Context ("light mode rebuilt to the dark standard") and the light-mode half of Decision 3 (world.css "the derived tier for both modes") no longer describe what the apex renders; the token contract, the sheet split, the plates and the sentinel rule stand. Also the landing direction's pick of option 3 in `docs/design/<redacted>.md` §5/§6 (2026-08-27): option 4, "dark-only landing", is the one taken after all, widened to every apex page.
8
+ - **Interacts with:** ADR 0062 §3 (the pack's `theme.ui` is one-mode — light values — and is still spliced as the `:root`; the dark blocks override it exactly as before), the `ui-design` module's kit (ADR 0198 line; `modes` in a states file), the hall's own switch (`modules/hall-ui/public/shell.js`, `hall-theme`), the next task in the chain (1003337: a rendered space backdrop for the field — a black-ground plate, which is what a single mode makes possible).
9
+
10
+ ## Context
11
+
12
+ The apex shipped with a real, tested light mode: the world round's light landing was called weak, the landing round offered four answers (`<redacted>.md` §5), and on 2026-08-27 the owner picked "light rebuilt to the dark standard" — the chrome as alpha cutouts on paper — over "dark-only landing". The build made both modes real: every dark rule written twice (`:root[data-mode="dark"]` and its `prefers-color-scheme` twin), a pre-paint script on every apex page reading `?mode=`, the persisted `cb-color-mode` choice and the OS preference, a 44px moon/sun glyph in both bars, the kit rendering every state in both modes, and contrast measured in both.
13
+
14
+ Reviewing the planets (task 1003319), the owner saw the two grounds side by side and chose one: the apex commits to dark, so the field can carry a rendered space backdrop (a black-ground plate composites with nothing to hide; a pale ground would need a second, cut-out material for every plate), and the light/dark switch stays what it already is in the builders' hall — the hall's own, on its own key.
15
+
16
+ Three facts shaped the shape of the change:
17
+
18
+ 1. **A fixed attribute beats a script.** `data-mode="dark"` on `<html>` in the served markup selects the same dark blocks the toggle used to select, before first paint, with nothing to flash, nothing to persist and nothing for the OS preference to reach — `:root[data-mode="dark"]` wins under `prefers-color-scheme: light`, and the `:root:not([data-mode="light"])` twin agrees under dark. The pack's one-mode `:root` (ADR 0062 §3) is untouched.
19
+ 2. **The light tier is load-bearing for tests, not for pixels.** `tests/world_tokens.mjs` and `tests/cosmos_token_contrast.mjs` measure every light pair against AA, and the twins rule is pinned on both pages. Deleting the tier in the same task would be a second, larger diff under a UI change the owner has not seen yet; leaving it costs nothing a visitor can see.
20
+ 3. **The kit had no way to say "one mode".** `render.js` walked `MODES` unless `--modes` was passed, and its floor audit flags `data-mode "dark" under a light scheme` — which is now the correct state of every apex page. A states file needs to declare the modes its page renders.
21
+
22
+ ## Decision
23
+
24
+ 1. **Every apex page pins `data-mode="dark"` on `<html>`**: `/`, `/projects`, `/privacy`, `/terms`, `/contact`. The pre-paint mode scripts leave all five pages; `cb-color-mode` is neither read nor written on the apex; `?mode=` no longer walks a second mode on the landing; no script calls `matchMedia('(prefers-color-scheme: dark)')`.
25
+ 2. **The mode glyph leaves both bars** — the landing's `#mode` button and the hub's `#modeToggle`, their moon/sun SVGs, the `.modeBtn` rules (page-local on the landing, `cosmos.css` for the hub, both under-900 variants), the icon-swap twins, and the hub's `resolvedMode` / `paintModeToggle` wiring. The bar's right side closes up: Projects, then the identity slot.
26
+ 3. **Light is the builders' hall's alone.** The hall's switch (`hall-theme`) is untouched and stays the only light/dark control on the platform.
27
+ 4. **The light tier stays for now.** `world.css` and `cosmos.css` keep their light values and their dark twins; the dark-twins rule in `DESIGN.md` and the `/design` playbook stands as written until the tier's own removal, which is a follow-up task, not this one. The contrast tests keep measuring the light pairs meanwhile.
28
+ 5. **The kit learns `modes`.** A states file may declare `"modes": ["dark"]` (validated: a non-empty subset of `dark` / `light`); `render.js` takes it as the default where `--modes` is not passed. `index.states.json` and `projects.states.json` declare `["dark"]` and set `modeQuery: false`; the hub's mode-toggle probe is gone.
29
+ 6. **The record.** `DESIGN.md` gains a Modes section and loses the `mode-toggle` component row; both direction records carry a dated note; the copy registry regenerates (the two toggle labels leave it); the tests that pinned the toggle now pin its absence and the fixed attribute (`tests/landing_page.mjs`, `tests/projects_hub.mjs`, `tests/projects_hub_pre_uat.mjs`, `tests/landing_legal_pages.mjs`, `tests/ui_design_kit.mjs`).
30
+
31
+ ## Consequences
32
+
33
+ - A visitor whose OS prefers light sees the dark apex; a visitor who had stored `light` on the apex before this change sees dark (the key is simply never read). The hall keeps whatever they chose there.
34
+ - The three alpha cutouts (`--plate-*-cut`) are no longer a light-mode material on the landing's hero; they remain the bongo pair's closing figure and the planets' masks (task 1003319), so they stay in `public-landing/assets/world/`.
35
+ - The next task (1003337) can treat the field's ground as black: a rendered deep-space plate, `cover`, still or a slow transform drift, dead under reduced motion.
36
+ - Rejected: keeping the toggle but defaulting dark (the owner's ask was one mode, not a default); deleting the light tier here (a larger diff than the decision needs, under a change not yet reviewed); moving `--modes dark` into every kit invocation instead of the states file (the file is the page's contract; the flag is a session's override).
@@ -291,5 +291,6 @@ This keeps the decision history honest and traceable.
291
291
  | 0201 | [**An application is the project's own `access_requests` row, vouched for by a hub-signed assertion carried in a HEADER; the record it carries is resolved live and never stored** ([task 1002283](https://cloudbongos.com/builders#/task/1002283), goal 1000045 — public builder profiles, C3/C4). The join relay (`POST /my-projects/join`) already posts `{github_login, display_name, note}` to the target's PUBLIC, unauthenticated `POST /access-requests` — presenting nothing the applicant could not have typed into the project's own landing page. Attaching a cross-project record to a login nobody vouched for turns the owner's queue into an impersonation surface: file a request naming a well-known builder, the owner reads that builder's track record beside it and approves, and whoever holds that GitHub account signs in. So the record is the thing that makes the unauthenticated write dangerous, and C4 cannot be built without closing it. Decisions: **D1** the application stays an `access_requests` row on the target — `status='invited'` IS what `hasInvitedAccessRequest` reads, so a parallel record would need a second branch in `firstTimeAdmissionBlocked`, the one decision that exists as one function to prevent drift; the migration adds only `applicant_github_id text` (core's own type) + `vouched_at`, the non-null id IS the vouch mark, and the console wave's `kind`/`created_by` stay a separate additive migration; the hub keeps a STATUSLESS echo `(github_id, client_id, applied_at)` so the applicant's own cards can say "you applied on <date>" without polling every project — it may never claim what the project decided (an approval becomes visible the way membership always does, via the check-in), and it ages out at 30 days; re-applying answers `requested`, not 409. **D2** the hub signs an audience-scoped `purpose: 'application'` assertion with the existing `mintHubAssertion`, verified OFFLINE by the existing `verifyHubAssertion` against the already-provisioned `<PREFIX>_HUB_PUBLIC_KEY` — no new secret, no apply-time hub call — and it travels in `<redacted>` because `validateOrRespond` is STRICT by default: a body field would 400 on every older pin, and `joinRelayOutcome` reads a 400 as "could not be reached", breaking applications to most projects for good (the CLI's device exchange carries its assertion in the body because that route was new; this one is not). A missing or invalid assertion writes the row UNVOUCHED, never refuses — refusing locks out an older hub and hands an attacker a denial vector. The record itself is never copied: the row stores an identity (+ the handle, since `GET /profiles/:handle` is the addressed read), and the REVIEWER'S BROWSER fetches the hub's already-public, already-CORS'd, already-`no-store` profile at render, where `profile_state='active' AND NOT hide_stats` is applied inside the module — so C2's live hide is honoured by construction with no cache to outlive it, and a hub outage degrades to "record unavailable" beside a queue that still works. An instance→hub server pull was rejected on ADR 0171 D1's own grounds. A private account's application carries name + handle + note in V1; the D3 sliver needs `project.recruit`, which the hub cannot check cross-origin. **D3** "project owner" is the project's OWN archon — the registrant is whoever `maybeSeatFirstAdmin` seated, delegates are whoever that archon grants on that instance, and because the instance IS the project the per-project-scoped-permission problem dissolves; the check is the atom that already guards the act, `access_request.review` (floor archon), and this goal mints NO new permission (widening the read half is the console wave's `project.recruit`). `platform_identity_projects.owner_github_id` stays advisory and is never a gate — a hub-held owner list consulted before an admission is the inversion ADR 0141 exists to prevent. **D4** three statuses, unchanged: `invited` IS the approval and the acceptance act is signing in (an `accepted` state would be a second place membership is asserted, free to drift from the one that admits); rescind is `invited → dismissed`, which the PATCH must learn to accept (it resolves only from `pending` today) and which must never pretend to remove a member who already signed in; an `invited` row expires read-time at 30 days whatever created it, while an application never expires because a stale `pending` admits nobody; approve/decline are idempotent on the value they hold. Rejected: a cross-project `applications` table on either side; a stored profile snapshot; the assertion in the body; refusing an unvouched application; the server-side pull; reading `owner_github_id` as authorization; a new "project owner" atom; an `accepted` status.](<redacted>.md) | platform identity / applications |
292
292
  | 0202 | [**A connection is one directed row on the platform account, and every degree label is computed over the graph the viewer is allowed to see** ([task 1002294](https://cloudbongos.com/builders#/task/1002294), goal 1000045 criterion C6 — the design spike for the connections wave). Criterion C6 asks for LinkedIn-shaped connections; the cross-project data plane it must sit on is account-global (ADR 0141) and governed by an owner-signed privacy matrix (`docs/specs/<redacted>.md` D1/D2), where ADR 0171 D4 already bans "a count plus a hidden total" as a leak by subtraction. Decisions: (1) **one directed request row** on a new `platform_identity_connections` — `requester`/`addressee` kept because the inbox, cancel and cooldown all need to know who asked, with `pair_lo`/`pair_hi` GENERATED from LEAST/GREATEST and a partial unique index over `pending|accepted` so a duplicate AND a simultaneous reciprocal request are database errors, not route bugs; module-owned and `platform_identity_`-namespaced (ADR 0083 §5). (2) The `goal_membership_requests` lifecycle (`pending → accepted|rejected|cancelled`, atomic resolve-and-act) with three deliberate divergences: a decline is **silent**, a re-ask inside its 90-day cooldown is **swallowed and answered as if it worked** (ADR 0194 §3 applied to a person — a 409 saying "declined" would disclose what the silence protects), and pending requests expire at **30 days read-time** (privacy spec D4), with expiry resolved in the same statement that inserts, since `now()` cannot live in an index predicate. Remove **hard-deletes** — a "A removed B" tombstone is data neither party consented to keep and no read path uses. (3) Degree = a **recursive CTE seeded at the viewer**, `DEGREE_MAX = 3` with `FANOUT_1`/`FANOUT_2` caps and a deterministic frontier order; past the caps the label is `null` ("out of network"), never a number the query did not establish. Envelope stated honestly: single-digit ms at hub scale, caps bite around 10⁴ accounts, and they convert a hub-heavy account's millions-wide 3-hop into a *missing label* on a page that still renders. (4) Connections get **no predicate of their own** — they consume task 1002967's single effective-visibility reader, published as JS and as `accountVisibleSql(alias)` (the ADR 0182 form); `profile_state='active'` floors the feature, a private account answers **404 not 403** and never appears in a public list, `hide_stats` suppresses the numbers beside an edge but not the edge, degree is an **own-scope read** so viewer-relative labels coexist with viewer-independent public responses — and every count is the length of the array the viewer may see. (5) "Builders you may know" from mutuals + shared projects + recency, one explainable linear score, a named project only where its catalogue row is publicly listed; shared goals refused (instance-local), guilds a reserved empty slot, and **Discord refused outright** (outside the trust boundary; the hub stores no Discord identity), as are the GitHub follower graph and address-book import. Rejected: two mirrored rows on accept; a symmetric edge with no requester; a core table beside `builders`; a materialised closure/adjacency table (privacy-filtered at write time = a cached visibility decision, which ADR 0171 D2 forbids); an in-process graph cache; a graph database. Deferred and named: a connections-specific hide toggle, blocking, what an accepted connection unlocks on a private account, and notifications beyond the existing attention card. Exposes to the guild/orb wave: `neighbours`, `degreeBetween`, `mutualCount` — **not** a stored strength scalar.](<redacted>.md) | platform identity / privacy / social graph |
293
293
  | 0203 | [**The doorway changelog leaves `src/module-api.js` — the CI auto-patch carrier appends to a markdown ledger instead** ([task 1003335](https://cloudbongos.com/builders#/task/1003335)). Amends [ADR 0161](<redacted>.md) §2. The `CORE_VERSION` release history lived as a comment block inside the doorway file, and ADR 0161's carrier appends two lines to it on EVERY merge-triggered release, pushed by `github-actions[bot]` straight to `main` — bypassing the `unit` gate it breaks. Release 1.19.407 took the file to 1501 lines, one over the `oversized_file_count` ratchet: `unit` went red on `main` and every open PR inherited it, self-inflicting and monotonic. Decision: the ledger moves to `docs/module-api-changelog.md` — markdown, which `fitness-ratchets.js` (`git ls-files '*.js'`) structurally never counts, so it can grow forever. All 1222 lines / 448 versions moved verbatim (only the `// ` marker stripped, kept in a fenced block so the hanging indent survives); the `const CORE_VERSION` literal and its line shape do NOT move, so every reader that greps it is untouched. `bump-version.js` transforms both files before writing either and refuses a half-applied bump; `publish.yml` stages both, pinned by `tests/bump_version.mjs`; the file is registered in `PUBLISH_ALLOWLIST` so the history keeps shipping inside `@bongos/core`; `src/module-api.js` keeps a pointer doc-comment where the block was. Rejected: trimming entries in place (buys one release), raising the baseline (out of policy per `config/fitness-baselines.json`'s own `_comment`), exempting the file from the ratchet.](<redacted>.md) | build pipeline / distribution |
294
+ | 0204 | [**The apex is dark only; light is the builders' hall's** ([task 1003336](https://cloudbongos.com/builders#/task/1003336), goal 1000080). Supersedes in part [ADR 0196](<redacted>.md) (the light-mode half of the landing build) and the landing direction's 2026-08-27 pick of "light rebuilt to the dark standard". The owner, reviewing the planets: "only black or only white is a bit bland… leaning towards only dark mode for this page and keep the dark/light mode to be solely for the builder hall", confirmed as the WHOLE apex. Decision: `/`, `/projects`, `/privacy`, `/terms` and `/contact` pin `data-mode="dark"` on `<html>` — no pre-paint script, no `cb-color-mode`, no `?mode=`, no OS-preference read; the moon/sun glyph and its wiring leave both bars; the hall's own `hall-theme` switch is the platform's only light/dark control. The light tier of `world.css` / `cosmos.css` and the dark-twins rule STAY until the tier's own removal (the light-pair contrast tests keep measuring). The kit learns `"modes": ["dark"]` in a states file (validated; `render.js` takes it as the default). Rejected: a dark default with the toggle kept; deleting the light tier in the same diff; `--modes dark` on every kit call instead of the page's contract.](<redacted>.md) | apex / design system |
294
295
 
295
296
  > ⚠️ **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.