@bongos/core 1.19.477 → 1.19.479

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.bongos-core.json +73 -38
  2. package/.claude/skills/design/SKILL.md +6 -2
  3. package/clients/bongos-client/README.md +1 -1
  4. package/clients/bongos-client/bongos-client.global.js +4 -0
  5. package/clients/bongos-client/index.cjs +4 -0
  6. package/clients/bongos-client/index.d.ts +5 -1
  7. package/clients/bongos-client/index.mjs +4 -0
  8. package/docs/adr/0230-a-look-skill-is-a-composition-grammar-the-palette-is-the-pack.md +36 -0
  9. package/docs/adr/README.md +1 -0
  10. package/docs/api/openapi.json +84 -3
  11. package/docs/api-reference.md +5 -3
  12. package/docs/copy-inventory.md +6 -6
  13. package/docs/copy-registry.json +6 -6
  14. package/docs/file-map.md +1 -1
  15. package/docs/module-api-changelog.md +4 -0
  16. package/modules/dev-box/app/src/vendor/bongos-client.cjs +4 -0
  17. package/modules/economy/credits.js +78 -0
  18. package/modules/economy/module.json +1 -1
  19. package/modules/economy/reward.js +4 -0
  20. package/modules/economy/routes/credits.js +151 -0
  21. package/modules/hall-ui/public/md-reader.js +24 -1
  22. package/modules/lifecycle/closeness.js +87 -37
  23. package/modules/lifecycle/routes/closeness.js +17 -8
  24. package/modules/platform-identity/platform-identity.js +1 -1
  25. package/modules/ui-design/module.json +1 -1
  26. package/modules/ui-design/skills/README.md +6 -2
  27. package/modules/ui-design/skills/gpt-taste/SKILL.md +110 -0
  28. package/modules/ui-design/skills/industrial-brutalist-ui/SKILL.md +110 -0
  29. package/modules/ui-design/skills/minimalist-ui/SKILL.md +103 -0
  30. package/modules/ui-design/skills/stitch-design-taste/SKILL.md +91 -0
  31. package/package-lock.json +2 -2
  32. package/package.json +1 -1
  33. package/src/module-api.js +1 -1
  34. package/tests/closeness.mjs +151 -31
  35. package/tests/credit_ledger_read.mjs +347 -0
  36. package/tests/hall_reading_world.mjs +80 -0
  37. package/tests/own_scope_guard.mjs +24 -2
  38. package/tests/ui_design_skills.mjs +56 -1
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.477",
6
- "core_contract": "1.19.477",
7
- "source_commit": "17d71953a32ddb4b8006ce2c0ed1d915b815ed1c",
5
+ "core_version": "1.19.479",
6
+ "core_contract": "1.19.479",
7
+ "source_commit": "10ddc4c5e1e7df8be68dd6dace0eb42303cbe53a",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-02T17:36:21.154Z",
9
+ "built_at": "2026-09-02T18:05:59.995Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 413,
12
+ "docs_redacted": 418,
13
13
  "agent_docs_stubbed": 24,
14
- "functional_verbatim": 1838,
14
+ "functional_verbatim": 1840,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2275,
20
- "tree_sha256": "dc88e652d6b7674e287e406b3397118f0e2af3e0346c2f234602da8ea24ff35b",
19
+ "file_count": 2282,
20
+ "tree_sha256": "2cb64137d54513737bd860e9726a70eb9e646ab4b86b17a9ade984e4d98eb497",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -127,7 +127,7 @@
127
127
  {
128
128
  "path": ".claude/skills/design/SKILL.md",
129
129
  "mode": "0000644",
130
- "sha256": "bbb135d166a4e17b6059506f794c47c27740a063a068f1ea28c62a0aee7728b0"
130
+ "sha256": "2b562ed7586653101b556c37a727a726abf7072e18c3f14b0eb5cb84df82bf55"
131
131
  },
132
132
  {
133
133
  "path": ".claude/skills/dev/SKILL.md",
@@ -362,12 +362,12 @@
362
362
  {
363
363
  "path": "clients/bongos-client/README.md",
364
364
  "mode": "0000644",
365
- "sha256": "6ad13168a2196e29e37c2810108686b3c24f30f739691634f9085ebfcd1fc804"
365
+ "sha256": "bcea7262c68e2e188b824e2b7eceeac71a277ba5b41c9611a898085f0f0f3e4f"
366
366
  },
367
367
  {
368
368
  "path": "clients/bongos-client/bongos-client.global.js",
369
369
  "mode": "0000644",
370
- "sha256": "dfaca6bbdd87f2d32b1684bbddd7bb4454367ccf1624a9bd5b38b571dd3708db"
370
+ "sha256": "3ca40bc7e4a83a1ef350a48cac85f1255b8cefe7f53cca511219daf4c6c65488"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -377,17 +377,17 @@
377
377
  {
378
378
  "path": "clients/bongos-client/index.cjs",
379
379
  "mode": "0000644",
380
- "sha256": "92bcaf81301220166e1126d65492ecc011b3b2fac94e594bf22f8049aa45aece"
380
+ "sha256": "50bc31cac788fe598020d06dcfeadbc321d6c1c9b54138d9fe5160eaece6ed65"
381
381
  },
382
382
  {
383
383
  "path": "clients/bongos-client/index.d.ts",
384
384
  "mode": "0000644",
385
- "sha256": "6e1ae5c410c8796df7efcdcd9cbd0ccebe1075da8bc18d503c50196d0e7db683"
385
+ "sha256": "df0f38eee9419bb2981fed70d5a6810f5c0e3e5fc578ca6b1f84e1bb43524eec"
386
386
  },
387
387
  {
388
388
  "path": "clients/bongos-client/index.mjs",
389
389
  "mode": "0000644",
390
- "sha256": "cf02ec862ca9fcf7700ed2566c2e148c83c763d9194a450a09cb3d191ad4c90b"
390
+ "sha256": "f0d6c047ce222dd4c2f31bd3a488d501f6f3ca31ff006961e070461d8f52528c"
391
391
  },
392
392
  {
393
393
  "path": "clients/bongos-client/package.json",
@@ -1654,20 +1654,25 @@
1654
1654
  "mode": "0000644",
1655
1655
  "sha256": "9166e49d44a97a1bb99d5604fb19579eaa1f3a491026bcf84538ecd5c0494880"
1656
1656
  },
1657
+ {
1658
+ "path": "docs/adr/0230-a-look-skill-is-a-composition-grammar-the-palette-is-the-pack.md",
1659
+ "mode": "0000644",
1660
+ "sha256": "a9163be00fa701f69f047a1129db375b433bdcae3430f0776a184d78ead24af9"
1661
+ },
1657
1662
  {
1658
1663
  "path": "docs/adr/README.md",
1659
1664
  "mode": "0000644",
1660
- "sha256": "4a6c61e9643282e9754f845ce4afb245c9c76b1eb827fc8ad52b973e594bd950"
1665
+ "sha256": "55ec492975735a3ba97235a67ac84e94fa993d98637badf0ead748221312bda4"
1661
1666
  },
1662
1667
  {
1663
1668
  "path": "docs/api-reference.md",
1664
1669
  "mode": "0000644",
1665
- "sha256": "c8a913a5ecb49f29ef05a6ee3f12725da23c777f720600847d2d8010815f2588"
1670
+ "sha256": "415a05d22faa1125fea0bf41251e4e6cdb5e45c82da81f6e70c027e8249237b2"
1666
1671
  },
1667
1672
  {
1668
1673
  "path": "docs/api/openapi.json",
1669
1674
  "mode": "0000644",
1670
- "sha256": "fa675542b54c8bbd96530ecaac630deaf9873cc9091714eb9fde660e5af2ad4e"
1675
+ "sha256": "168549601bd155157cd57ecca98fedc54a827c0ca1f873d2c46ddfe4a7b2df46"
1671
1676
  },
1672
1677
  {
1673
1678
  "path": "docs/architecture.md",
@@ -1692,12 +1697,12 @@
1692
1697
  {
1693
1698
  "path": "docs/copy-inventory.md",
1694
1699
  "mode": "0000644",
1695
- "sha256": "504ab0bb1e8cd0c643a0aa27ea7e018278fc86d573291ccb654cc936488eb0dc"
1700
+ "sha256": "3aecb3448eabb9c945a3455432c80a1913bbc11004e38bed0735c6d763feb6ef"
1696
1701
  },
1697
1702
  {
1698
1703
  "path": "docs/copy-registry.json",
1699
1704
  "mode": "0000644",
1700
- "sha256": "e8b3759291fa7f9853bb901e230dcfeb75d5f8e8f4908983f65c2a82c36ae46f"
1705
+ "sha256": "586588197cadf5c8b7f97f3689a1f83333d1c6d21eabbac63d3239ba9d97ed70"
1701
1706
  },
1702
1707
  {
1703
1708
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2137,7 +2142,7 @@
2137
2142
  {
2138
2143
  "path": "docs/file-map.md",
2139
2144
  "mode": "0000644",
2140
- "sha256": "ad3830c5ce7650d78c18dbd03c03c0544cbdc9f0dc018c4e09da1cf5bdf67d21"
2145
+ "sha256": "1cac56ec4e482c9a14cdaef30e8dfe2d31c6c759252472e11d721bda4ee129ab"
2141
2146
  },
2142
2147
  {
2143
2148
  "path": "docs/handoff-template.md",
@@ -2147,7 +2152,7 @@
2147
2152
  {
2148
2153
  "path": "docs/module-api-changelog.md",
2149
2154
  "mode": "0000644",
2150
- "sha256": "d04efaed57b08373781ce55244d916cca3302daecd5c6c5c3e7fb93bfcdcf950"
2155
+ "sha256": "21c70bd8a32361038e14920c58ededfb34aa13c2c1f4592242b0617fe4c8677a"
2151
2156
  },
2152
2157
  {
2153
2158
  "path": "docs/modules-contract.md",
@@ -3502,7 +3507,7 @@
3502
3507
  {
3503
3508
  "path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
3504
3509
  "mode": "0000644",
3505
- "sha256": "92bcaf81301220166e1126d65492ecc011b3b2fac94e594bf22f8049aa45aece"
3510
+ "sha256": "50bc31cac788fe598020d06dcfeadbc321d6c1c9b54138d9fe5160eaece6ed65"
3506
3511
  },
3507
3512
  {
3508
3513
  "path": "modules/dev-box/app/test/unit.mjs",
@@ -3677,7 +3682,7 @@
3677
3682
  {
3678
3683
  "path": "modules/economy/credits.js",
3679
3684
  "mode": "0000644",
3680
- "sha256": "06f1cc7080509864ea4f474627a7a35de8348fcf4f935a13fc62da38e2a67fa8"
3685
+ "sha256": "594d0eee9447bbc4b0e5dde91e2aba58bd762cf7e046c466df0527ec6ba24138"
3681
3686
  },
3682
3687
  {
3683
3688
  "path": "modules/economy/migrations/economy_001_fix_gds_shipper_description.sql",
@@ -3687,7 +3692,7 @@
3687
3692
  {
3688
3693
  "path": "modules/economy/module.json",
3689
3694
  "mode": "0000644",
3690
- "sha256": "b8b3a4add551b32bc625dca0390afc2176dcd9e433b24d21128dd6e249e70623"
3695
+ "sha256": "1916409c7cf0bf58c986eea43a89c9bf07df0ec17a65a3aa4b328ef0ee196545"
3691
3696
  },
3692
3697
  {
3693
3698
  "path": "modules/economy/policy.js",
@@ -3697,13 +3702,18 @@
3697
3702
  {
3698
3703
  "path": "modules/economy/reward.js",
3699
3704
  "mode": "0000644",
3700
- "sha256": "13cc932402c3cf0d2154507c6e6a462aeb98520a2214b8561ec01a6bb9245fd6"
3705
+ "sha256": "6b13f1f0a1b9b1a56f5ed12a31008f20002cdb501da4e9f95ef2e28441eb56f9"
3701
3706
  },
3702
3707
  {
3703
3708
  "path": "modules/economy/routes/cost.js",
3704
3709
  "mode": "0000644",
3705
3710
  "sha256": "4113b736359f09d6869795800d52394603823b570263dd1852281b35e6bb2485"
3706
3711
  },
3712
+ {
3713
+ "path": "modules/economy/routes/credits.js",
3714
+ "mode": "0000644",
3715
+ "sha256": "0363555567d6b496c80eee71b686094ca5d18b6c987a15cd1ad4dca2458f2397"
3716
+ },
3707
3717
  {
3708
3718
  "path": "modules/economy/routes/leaderboard.js",
3709
3719
  "mode": "0000644",
@@ -4332,7 +4342,7 @@
4332
4342
  {
4333
4343
  "path": "modules/hall-ui/public/md-reader.js",
4334
4344
  "mode": "0000644",
4335
- "sha256": "ac9cc29bf8f480c7bd9560309a36a540e33421d65bfdbdbd2d24cd9808dc51d1"
4345
+ "sha256": "89c3def79578cf30ad3757d3cac9c2242dfece978758d7c256c2b4b8963cb201"
4336
4346
  },
4337
4347
  {
4338
4348
  "path": "modules/hall-ui/public/modules.css",
@@ -4752,7 +4762,7 @@
4752
4762
  {
4753
4763
  "path": "modules/lifecycle/closeness.js",
4754
4764
  "mode": "0000644",
4755
- "sha256": "f5668020c115a6d356a74603dc4a7229ddfdb8d5015a22f871a35386a869fe58"
4765
+ "sha256": "4ea4fe1c93ffe6d6f42af31d96dfe402d7dbccb4a5825b71c571024548a87c25"
4756
4766
  },
4757
4767
  {
4758
4768
  "path": "modules/lifecycle/conflict-resolve.js",
@@ -4962,7 +4972,7 @@
4962
4972
  {
4963
4973
  "path": "modules/lifecycle/routes/closeness.js",
4964
4974
  "mode": "0000644",
4965
- "sha256": "1950ba9d20f925fa1ecbe7fb37d35a5b80045c556c6f76caa90b82e213b7db88"
4975
+ "sha256": "1ad8e353ead5c3fe39fadc1d48a2fc65725762cc298e206464ef242f7fdd292d"
4966
4976
  },
4967
4977
  {
4968
4978
  "path": "modules/lifecycle/routes/dependencies.js",
@@ -5312,7 +5322,7 @@
5312
5322
  {
5313
5323
  "path": "modules/platform-identity/platform-identity.js",
5314
5324
  "mode": "0000644",
5315
- "sha256": "1542edccc61a1cdb77540f5b6521a91477234af03cdde9178a1ed5516363e1fd"
5325
+ "sha256": "c43bda216cc9c6ec1788dd5d6ef4978594c1ab6db61ad6af33ed8ce451594899"
5316
5326
  },
5317
5327
  {
5318
5328
  "path": "modules/platform-identity/pollers/code-sweep.js",
@@ -6437,7 +6447,7 @@
6437
6447
  {
6438
6448
  "path": "modules/ui-design/module.json",
6439
6449
  "mode": "0000644",
6440
- "sha256": "0f88b29039e01fb908e4351d3fdac8198206782a0afdbf5156da6e02ad312d26"
6450
+ "sha256": "5a53e893524c48deef3e62fcb2765dc9b3f0a96f76309ba86c99df194abc79aa"
6441
6451
  },
6442
6452
  {
6443
6453
  "path": "modules/ui-design/scripts/design-sync.js",
@@ -6462,7 +6472,7 @@
6462
6472
  {
6463
6473
  "path": "modules/ui-design/skills/README.md",
6464
6474
  "mode": "0000644",
6465
- "sha256": "ddc9a2b8788d3e41f1d3ae285d56c75ecb6e7a9d4aa003a0db55f4d38ff24d4a"
6475
+ "sha256": "8d25a88e882979a98e859974c4ced8a8d27fb2c5bd57d6bca7be709fc052ca75"
6466
6476
  },
6467
6477
  {
6468
6478
  "path": "modules/ui-design/skills/brandkit/SKILL.md",
@@ -6479,6 +6489,11 @@
6479
6489
  "mode": "0000644",
6480
6490
  "sha256": "ee07bdde8e388b2863431673390d4bff74ee1296920ebcb07b529060eb7f8959"
6481
6491
  },
6492
+ {
6493
+ "path": "modules/ui-design/skills/gpt-taste/SKILL.md",
6494
+ "mode": "0000644",
6495
+ "sha256": "3e2e4802407df6763db372c27f3deaaf8f9b6233778668ddeaff65dec147ac7c"
6496
+ },
6482
6497
  {
6483
6498
  "path": "modules/ui-design/skills/high-end-visual-design/SKILL.md",
6484
6499
  "mode": "0000644",
@@ -6594,6 +6609,16 @@
6594
6609
  "mode": "0000644",
6595
6610
  "sha256": "d960ee789a1b5d44c06bab53d2a661800457960cb121cf1496ba928792fa9307"
6596
6611
  },
6612
+ {
6613
+ "path": "modules/ui-design/skills/industrial-brutalist-ui/SKILL.md",
6614
+ "mode": "0000644",
6615
+ "sha256": "4d781aa002138bdad572dfcae0dc6f1175fe070ee37fa8f3ef9a0f6af08e039b"
6616
+ },
6617
+ {
6618
+ "path": "modules/ui-design/skills/minimalist-ui/SKILL.md",
6619
+ "mode": "0000644",
6620
+ "sha256": "b7b22a1ab8aa148ac4fc8573d7088c6ff207beb53f628009e7cfc363c6bbd2c2"
6621
+ },
6597
6622
  {
6598
6623
  "path": "modules/ui-design/skills/policy.json",
6599
6624
  "mode": "0000644",
@@ -6604,6 +6629,11 @@
6604
6629
  "mode": "0000644",
6605
6630
  "sha256": "22e8f7ea0d206b3f4b2243b986a4dcd10df4ba0198aa063e76ef4d2788fec55d"
6606
6631
  },
6632
+ {
6633
+ "path": "modules/ui-design/skills/stitch-design-taste/SKILL.md",
6634
+ "mode": "0000644",
6635
+ "sha256": "f8c6c38ccb5fea529e86731005e8bbf231a9131c890010a29129c06195f48945"
6636
+ },
6607
6637
  {
6608
6638
  "path": "modules/ui-design/styles/README.md",
6609
6639
  "mode": "0000644",
@@ -6692,12 +6722,12 @@
6692
6722
  {
6693
6723
  "path": "package-lock.json",
6694
6724
  "mode": "0000644",
6695
- "sha256": "61a5372ee6a0262a905396aa54a6a72f423e509308213dcc24dcc02e78b225c8"
6725
+ "sha256": "9ffa26ff1d228908ca60ad5e7cd808dc8bf0544d8575047d1921035a02ea9775"
6696
6726
  },
6697
6727
  {
6698
6728
  "path": "package.json",
6699
6729
  "mode": "0000644",
6700
- "sha256": "067fc518cdcae9e18db8cfe039dacef25a81586772c0c8c0105f8325f325ad34"
6730
+ "sha256": "769e71f6b493dd866574c9fb1633ef1dad344af65a151d19ed74cd07bc832a3e"
6701
6731
  },
6702
6732
  {
6703
6733
  "path": "public-docs/index.html",
@@ -8352,7 +8382,7 @@
8352
8382
  {
8353
8383
  "path": "src/module-api.js",
8354
8384
  "mode": "0000644",
8355
- "sha256": "80d23eb49ce424e573ed6bfed618610b58498eba45cc4756ca2739cc05831106"
8385
+ "sha256": "baddbaa3d45390694efbe255d10323466461ff51349d1720cc231a94a196a179"
8356
8386
  },
8357
8387
  {
8358
8388
  "path": "src/module-loader/catalog.js",
@@ -8917,7 +8947,7 @@
8917
8947
  {
8918
8948
  "path": "tests/closeness.mjs",
8919
8949
  "mode": "0000644",
8920
- "sha256": "b5c4791d84aa3126714c7b3188320dc4df984e282a086196ded2394f825295d1"
8950
+ "sha256": "be10e63b6a424914ba71537dbfa653dcb247b28b3e6a9a8caf4696268e4500cf"
8921
8951
  },
8922
8952
  {
8923
8953
  "path": "tests/cloud_bongos_pack.mjs",
@@ -9014,6 +9044,11 @@
9014
9044
  "mode": "0000644",
9015
9045
  "sha256": "dcb35adea926027490b7ca20a59fd596d2db097cc84ec004a372e922602098c8"
9016
9046
  },
9047
+ {
9048
+ "path": "tests/credit_ledger_read.mjs",
9049
+ "mode": "0000644",
9050
+ "sha256": "d7c96a67f1eda974a9387a47d12bf70d7f2125ea77c1ddb313e5a3feb47ae04f"
9051
+ },
9017
9052
  {
9018
9053
  "path": "tests/criterion_authoring_gate.mjs",
9019
9054
  "mode": "0000644",
@@ -9772,7 +9807,7 @@
9772
9807
  {
9773
9808
  "path": "tests/hall_reading_world.mjs",
9774
9809
  "mode": "0000644",
9775
- "sha256": "0639e14742626f0f75400a5dd462418ff4dba9ab9f28aa517a165f63c65046c3"
9810
+ "sha256": "f3e2a8865189646212733ee9a85d295543acc0309b4087a9eaf36d72426c4b4b"
9776
9811
  },
9777
9812
  {
9778
9813
  "path": "tests/hall_record_world.mjs",
@@ -10382,7 +10417,7 @@
10382
10417
  {
10383
10418
  "path": "tests/own_scope_guard.mjs",
10384
10419
  "mode": "0000644",
10385
- "sha256": "3c823f5ad58a6406ecc5b93a5f3f5271fd8400c8839ad0fa99c27bf49032c8d7"
10420
+ "sha256": "4ddff5b21edcbc682ff54ffc13c8ed643db4b8860ed55a7196822f0b40e9611e"
10386
10421
  },
10387
10422
  {
10388
10423
  "path": "tests/own_session_revoke.mjs",
@@ -11307,7 +11342,7 @@
11307
11342
  {
11308
11343
  "path": "tests/ui_design_skills.mjs",
11309
11344
  "mode": "0000644",
11310
- "sha256": "155aa8b197f52ec73d3654ac8cb15134998e4de81fbbf37e8d7e423efebb94b1"
11345
+ "sha256": "fd13a17493141b519051ad3a94104c13f79409b06904d129dc9bf13acd73fa58"
11311
11346
  },
11312
11347
  {
11313
11348
  "path": "tests/ui_design_styles.mjs",
@@ -59,14 +59,18 @@ Generated code uses the `--dt-*` variables; adapters write only `src/ui/<surface
59
59
 
60
60
  Third-party design skills reach a builder only through the module's vendoring policy ([`modules/ui-design/skills/README.md`](../../../modules/ui-design/skills/README.md), ADR 0198): scanned with `/scan-before-install` and reduced to `clean` or `caution`, a licence on the allowlist, a `PROVENANCE.md` sidecar, and the PLATFORM PREAMBLE that reads the instance's world before any taste rule. A skill the module ships is listed here by name, one line each, whether vendored or rebuilt in-house; a name that is not listed is not the module's, whatever a builder's own `~/.claude/skills` carries.
61
61
 
62
- - *None vendored (2026-08-28).* Both origins scanned for the scoped set — `pbakaus/impeccable`, and the eleven `Leonxlnx/taste-skill` skills (`minimalist-ui`, `industrial-brutalist-ui`, `gpt-taste`, `stitch-design-taste`, `image-to-code`, `imagegen-frontend-web`, `imagegen-frontend-mobile`, `brandkit`, and the four below) — reduced to `dangerous` at the scanner's deterministic floor and landed as rebuild specs (GDS tasks). The roster, the verdicts and the way to land one are in the README; vendoring one anyway is an owner override recorded in an ADR, not a session's call.
62
+ - *None vendored (2026-08-28).* Both origins scanned for the scoped set — `pbakaus/impeccable`, and the eleven `Leonxlnx/taste-skill` skills (`minimalist-ui`, `industrial-brutalist-ui`, `gpt-taste`, `stitch-design-taste`, `image-to-code`, `imagegen-frontend-web`, `imagegen-frontend-mobile`, `brandkit`, and the rest of the roster below) — reduced to `dangerous` at the scanner's deterministic floor and landed as rebuild specs (GDS tasks). The roster, the verdicts and the way to land one are in the README; vendoring one anyway is an owner override recorded in an ADR, not a session's call.
63
63
 
64
- **Rebuilt in-house from the specs** ([ADR 0220](../../../docs/adr/<redacted>.md), task 1003325; [ADR 0221](../../../docs/adr/<redacted>.md), task 1003326; [ADR 0222](../../../docs/adr/<redacted>.md), task 1003328): first-party skills at `modules/ui-design/skills/<name>/`, each opening with the same preamble, each naming its spec and what changed in translation. They run INSIDE the loop above: the world first, the style library as the palette source for a variant, images as hero plates only, every motion rule inside the Kill Switch, the kit as the pre-flight.
64
+ **Rebuilt in-house from the specs** ([ADR 0220](../../../docs/adr/<redacted>.md), task 1003325; [ADR 0221](../../../docs/adr/<redacted>.md), task 1003326; [ADR 0222](../../../docs/adr/<redacted>.md), task 1003328; [ADR 0230](../../../docs/adr/<redacted>.md), task 1003327): first-party skills at `modules/ui-design/skills/<name>/`, each opening with the same preamble, each naming its spec and what changed in translation. They run INSIDE the loop above: the world first, the style library as the palette source for a variant, images as hero plates only, every motion rule inside the Kill Switch, the kit as the pre-flight.
65
65
 
66
66
  - **design-taste-frontend** — the default taste skill for a landing page, a portfolio or a marketing surface: the brief read in one line, three dials from presets, one world locked for the page, hero and layout discipline, rationed decoration, a pre-flight the kit measures. Declines dashboards, tables, wizards and editors.
67
67
  - **design-taste-frontend-v1** — the earlier generation, kept distinct: a fixed baseline triple adapted in conversation, stack conventions for a served surface, the layout bans, full interaction cycles, the named vocabulary of premium patterns and the tile-grid archetypes.
68
68
  - **high-end-visual-design** — the agency-build polish pass: one texture archetype (the library's looks) and one layout archetype per project, the nested container anatomy where the world allows a container, the pill with its nested arrow disc, the spatial rhythm, choreography and scroll entry inside the Kill Switch.
69
69
  - **redesign-existing-projects** — the in-place upgrade: scan the stack, diagnose against the seven-group audit with the instance's world as the answer key, fix in impact-per-risk order, one group per commit; keeps the stack, never migrates frameworks, `probe.js` green before and after.
70
+ - **minimalist-ui** — the quiet editorial look: macro whitespace first, a capped measure, one display job and one body job, exactly one hairline weight in the whole sheet, washed accents measured against their own ink, flat tile cards with no shadow, box-less accordions and keycap shortcuts, one depth treatment per band. Declines dense surfaces; the nearest library look is `expedition`.
71
+ - **industrial-brutalist-ui** — the technical-document look: one archetype per project (Swiss industrial print or dark tactical terminal, never mixed) with the other mode still complete and measured, massive clamped uppercase display against fixed tracked-out mono metadata, the pack's terracotta as the one hazard accent and its sea as one terminal green, the hairline as a one-pixel grid gap, zero corner rounding, static halftone and scanline degradation.
72
+ - **gpt-taste** — the anti-default pass for a surface that came out looking like every other one: a written plan block before any markup whose selection is derived from the route and bumped against sibling surfaces, the four-stage structure, an ultra-wide hero held to two or three lines, a dense tile grid with zero empty cells, real scroll-driven motion in CSS. Pack-agnostic; it runs over whatever look is on.
73
+ - **stitch-design-taste** — the design contract document for an external screen-generating tool: four dials, eight fixed sections, descriptive language paired with exact values, the thirteen transcribed from the instance's pack and diffed rather than invented, and motion written as an intent brief for whoever codes the screens afterwards.
70
74
  - **impeccable** — the design-craft method as one skill with sub-commands: `impeccable <sub-command> <target>` loads exactly one of eighteen playbooks (shape, critique, audit, polish, harden, onboard, animate, colorize, typeset, layout, adapt, distill, clarify, optimize, document, extract, bolder, quieter); no argument prints a menu from live project signals and never auto-runs; a bare description is routed to the closest playbook; carries the craft floor (loaded right before UI is edited, never recited) and the bounded finish (build, one kit round, one batch of fixes, at most one confirming round, stop; a read-only reviewer that answers with one of four words). No hooks, no bypass agent, no telemetry, no live server: the live loop is the playwright plugin below and the headless loop is the kit; the detector is task 1003329; native mobile declines to this loop.
71
75
  - **imagegen-frontend-web** — the plate-making skill under the hero-only rule: text-free hero plates, hero objects, backdrops and orbs for the slots a composition already has (the count is the slot count, committed out loud), a composition anchor per plate that is not text-left image-right, one material / light / lens across the family, the pack as the palette lock, the instance's art pipeline key, and the pair-and-sidecar output contract (a black-ground JPEG for dark, an alpha WebP cutout for light, a `<file>.json` beside each). Never a section image, a comp or a screen; writes no page code.
72
76
  - **imagegen-frontend-mobile** — the same, for the 390 and 320 compositions: portrait mastheads and fields clear of the regions a phone reserves, the first view held to one focal point, a scrim under any text over a plate. A screen is the surface's states file rendered by the kit; no phone mockups, no flows of screens; a native app target declines to this loop.
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
5
5
  by hand; it regenerates when the spec changes, so it can never drift from the routes.
6
6
 
7
7
  - API version: **v1** (served at `/api/bongos/v1`)
8
- - 339 operations across 53 resource groups
8
+ - 341 operations across 53 resource groups
9
9
 
10
10
  ## Install
11
11
 
@@ -221,6 +221,8 @@ function createClient(opts = {}) {
221
221
  getBugAttachmentsName: (args) => request("GET", "/bug-attachments/{name}", { hasBody: false }, args),
222
222
  },
223
223
  "builders": {
224
+ // GET /builders/{builderId}/credits — rank: metic+archon — GET /builders/:builderId/credits
225
+ getBuildersBuilderIdCredits: (args) => request("GET", "/builders/{builderId}/credits", { hasBody: false }, args),
224
226
  // GET /builders/{id}/active-claims — rank: metic+archon — GET /builders/:id/active-claims
225
227
  getBuildersIdActiveClaims: (args) => request("GET", "/builders/{id}/active-claims", { hasBody: false }, args),
226
228
  // GET /builders/{id}/activity — rank: any-builder — GET /builders/:id/activity
@@ -503,6 +505,8 @@ function createClient(opts = {}) {
503
505
  getMeAchievements: (args) => request("GET", "/me/achievements", { hasBody: false }, args),
504
506
  // POST /me/anthropic-link — rank: any-builder — POST /me/anthropic-link
505
507
  postMeAnthropicLink: (args) => request("POST", "/me/anthropic-link", { hasBody: true }, args),
508
+ // GET /me/credits — rank: any-builder — GET /me/credits
509
+ getMeCredits: (args) => request("GET", "/me/credits", { hasBody: false }, args),
506
510
  // GET /me/cross-project — rank: any-builder — GET /me/cross-project
507
511
  getMeCrossProject: (args) => request("GET", "/me/cross-project", { hasBody: false }, args),
508
512
  // PATCH /me/cross-project — rank: any-builder — PATCH /me/cross-project
@@ -220,6 +220,8 @@ function createClient(opts = {}) {
220
220
  getBugAttachmentsName: (args) => request("GET", "/bug-attachments/{name}", { hasBody: false }, args),
221
221
  },
222
222
  "builders": {
223
+ // GET /builders/{builderId}/credits — rank: metic+archon — GET /builders/:builderId/credits
224
+ getBuildersBuilderIdCredits: (args) => request("GET", "/builders/{builderId}/credits", { hasBody: false }, args),
223
225
  // GET /builders/{id}/active-claims — rank: metic+archon — GET /builders/:id/active-claims
224
226
  getBuildersIdActiveClaims: (args) => request("GET", "/builders/{id}/active-claims", { hasBody: false }, args),
225
227
  // GET /builders/{id}/activity — rank: any-builder — GET /builders/:id/activity
@@ -502,6 +504,8 @@ function createClient(opts = {}) {
502
504
  getMeAchievements: (args) => request("GET", "/me/achievements", { hasBody: false }, args),
503
505
  // POST /me/anthropic-link — rank: any-builder — POST /me/anthropic-link
504
506
  postMeAnthropicLink: (args) => request("POST", "/me/anthropic-link", { hasBody: true }, args),
507
+ // GET /me/credits — rank: any-builder — GET /me/credits
508
+ getMeCredits: (args) => request("GET", "/me/credits", { hasBody: false }, args),
505
509
  // GET /me/cross-project — rank: any-builder — GET /me/cross-project
506
510
  getMeCrossProject: (args) => request("GET", "/me/cross-project", { hasBody: false }, args),
507
511
  // PATCH /me/cross-project — rank: any-builder — PATCH /me/cross-project
@@ -37,7 +37,7 @@ export interface GetBuildersIdOnboardingResponse { builder_id: unknown; onboardi
37
37
  export interface GetBuildersIdProfileResponse { builder: unknown; shipped_count: unknown; recent_ships: unknown; achievements: unknown; cross_project?: unknown; handle?: unknown }
38
38
  export interface GetBuildersMePendingRankChangeResponse { change: unknown; greeting?: unknown }
39
39
  export interface GetBuildersRosterResponse { builders: unknown; stale_hours: unknown; stale_hours_source: unknown }
40
- export interface GetClosenessForMeResponse { closeness: unknown; count: unknown }
40
+ export interface GetClosenessForMeResponse { closeness: unknown; count: unknown; returned: unknown }
41
41
  export interface GetClosenessWeightsResponse { weights: unknown; window_days: unknown; note: unknown }
42
42
  export interface GetClosenessWithBuilderIdResponse { closeness: unknown; why: unknown }
43
43
  export interface GetConnectionsDegreeHandleResponse { handle: unknown; degree: unknown; mutuals: unknown; mutual_count: unknown; truncated: unknown }
@@ -528,6 +528,8 @@ export interface BongosClient {
528
528
  getBugAttachmentsName(args?: RequestArgs): Promise<ApiResponse>;
529
529
  };
530
530
  "builders": {
531
+ /** GET /builders/{builderId}/credits — rank: metic+archon */
532
+ getBuildersBuilderIdCredits(args?: RequestArgs): Promise<ApiResponse>;
531
533
  /** GET /builders/{id}/active-claims — rank: metic+archon */
532
534
  getBuildersIdActiveClaims(args?: RequestArgs): Promise<GetBuildersIdActiveClaimsResponse>;
533
535
  /** GET /builders/{id}/activity — rank: any-builder */
@@ -810,6 +812,8 @@ export interface BongosClient {
810
812
  getMeAchievements(args?: RequestArgs): Promise<GetMeAchievementsResponse>;
811
813
  /** POST /me/anthropic-link — rank: any-builder */
812
814
  postMeAnthropicLink(args: RequestArgs & { body: PostMeAnthropicLinkRequest }): Promise<PostMeAnthropicLinkResponse>;
815
+ /** GET /me/credits — rank: any-builder */
816
+ getMeCredits(args?: RequestArgs): Promise<ApiResponse>;
813
817
  /** GET /me/cross-project — rank: any-builder */
814
818
  getMeCrossProject(args?: RequestArgs): Promise<GetMeCrossProjectResponse>;
815
819
  /** PATCH /me/cross-project — rank: any-builder */
@@ -217,6 +217,8 @@ export function createClient(opts = {}) {
217
217
  getBugAttachmentsName: (args) => request("GET", "/bug-attachments/{name}", { hasBody: false }, args),
218
218
  },
219
219
  "builders": {
220
+ // GET /builders/{builderId}/credits — rank: metic+archon — GET /builders/:builderId/credits
221
+ getBuildersBuilderIdCredits: (args) => request("GET", "/builders/{builderId}/credits", { hasBody: false }, args),
220
222
  // GET /builders/{id}/active-claims — rank: metic+archon — GET /builders/:id/active-claims
221
223
  getBuildersIdActiveClaims: (args) => request("GET", "/builders/{id}/active-claims", { hasBody: false }, args),
222
224
  // GET /builders/{id}/activity — rank: any-builder — GET /builders/:id/activity
@@ -499,6 +501,8 @@ export function createClient(opts = {}) {
499
501
  getMeAchievements: (args) => request("GET", "/me/achievements", { hasBody: false }, args),
500
502
  // POST /me/anthropic-link — rank: any-builder — POST /me/anthropic-link
501
503
  postMeAnthropicLink: (args) => request("POST", "/me/anthropic-link", { hasBody: true }, args),
504
+ // GET /me/credits — rank: any-builder — GET /me/credits
505
+ getMeCredits: (args) => request("GET", "/me/credits", { hasBody: false }, args),
502
506
  // GET /me/cross-project — rank: any-builder — GET /me/cross-project
503
507
  getMeCrossProject: (args) => request("GET", "/me/cross-project", { hasBody: false }, args),
504
508
  // PATCH /me/cross-project — rank: any-builder — PATCH /me/cross-project
@@ -0,0 +1,36 @@
1
+ # ADR 0230 — A look skill is a composition grammar; the palette is the pack and the texture is a library entry
2
+
3
+ - **Status:** accepted
4
+ - **Date:** 2026-09-02
5
+ - **Task:** [task 1003327](https://cloudbongos.com/builders#/task/1003327) (goal 1000083 — the ui-design module as a platform capability; criterion `uidesign-skills-in-house`)
6
+ - **Relates to:** [ADR 0198](<redacted>.md) (a dangerous verdict lands a spec, never a copy), [ADR 0219](<redacted>.md) (a look is a branding pack), [ADR 0220](<redacted>.md) (the landing shape of a rebuild), [ADR 0222](<redacted>.md) (the owner's imagery rule), [ADR 0223](0223-the-detector-is-two-tiers-in-the-kit.md) (the tells the pre-flights point at), [ADR 0196](<redacted>.md) (the token contract)
7
+
8
+ ## Context
9
+
10
+ The taste-skill rebuild spec ([task 1003325](https://cloudbongos.com/builders#/task/1003325)) carries four requirement groups that are unlike the other seven. `design-taste-frontend`, `high-end-visual-design` and `redesign-existing-projects` are **methods** — they tell an agent how to work. `minimalist-ui`, `industrial-brutalist-ui`, `gpt-taste` and `stitch-design-taste` are **looks**: upstream, each one shipped a palette, a set of faces, and in two cases an explicit instruction to install one.
11
+
12
+ That is exactly what this platform's contract forbids. A pack carries fifteen tokens and a page reads only those (ADR 0196); a look that wants a sixteenth is a contract change and an ADR (ADR 0219). Four skills that each hand an agent a warm bone canvas, an off-white document paper, a hazard red and a graded ambient background would be four silent forks of the world, indistinguishable in a diff from a page that simply broke the rules — and they would fight the style library, which already ships looks as packs an instance adopts through `config/branding.json`.
13
+
14
+ Three further collisions had to be settled rather than papered over:
15
+
16
+ 1. **One substrate per project** (brutalist) against **both modes on every page** (the platform floor, and the preamble's dark twins).
17
+ 2. **A random selection seeded from the prompt** (gpt-taste) against a repository where two sibling surfaces must be reconcilable a year later by reading the files.
18
+ 3. **An authored palette for a downstream tool** (stitch) against a world the instance already owns — a document that invents colours describes a different product than the one that will be built.
19
+
20
+ ## Decision
21
+
22
+ 1. **A look skill ships a composition grammar and no colours.** Its rules are structure, rhythm, type roles, component anatomy, motion and bans. Every colour it names is a `var()` or a `color-mix()` of the fifteen. The palette is the instance's pack; a variant is a **library entry** at `modules/ui-design/styles/`, and each look skill names the entry it was tuned against (`minimalist-ui` → `expedition`, `industrial-brutalist-ui` → `chrome-world` for the terminal archetype and `expedition` for the print one, `gpt-taste` → pack-agnostic, `stitch-design-taste` → whichever the document transcribes). A skill never adds a face: the pack's two stacks are the type system, and a face the look wants is a pack change.
23
+ 2. **A substrate becomes an archetype, and the other mode still ships.** `industrial-brutalist-ui` commits to one archetype per project — the archetype decides which mode the surface is *composed for*, and the other mode is the same composition on the other tier, complete, measured, and given its own shots. The upstream's "never both" survives as "never mixed in one interface", which is the part that was actually about craft.
24
+ 3. **The selection is deterministic and written down, not rolled.** `gpt-taste`'s plan block derives its hero architecture, its three component architectures and its two motion paradigms from the surface's own route, then bumps the index where a sibling surface already used that architecture, and records both. The upstream's anti-repetition goal is kept; its unreproducible mechanism is not. The block is written before any markup and carries the hero arithmetic, the grid-density proof and the measured contrast pairs.
25
+ 4. **A design document transcribes the world, it does not author one.** `stitch-design-taste` writes in the platform's own `DESIGN.md` frontmatter shape — the shape every library look already carries, so a document produced here reads back as a style — and its colour contract is the instance's thirteen with their real hex values and the instance's own roles, **diffed against the pack rather than retyped**. Its universal bans (no pure black, no serif in a dashboard) are defaults that the instance's `DESIGN.md` overrules, and the document says so in its own closing clause so the external tool is not told a different product exists.
26
+ 5. **The imagery rule survives the port intact.** The upstream's seeded placeholder photography (minimalist, gpt-taste) and its filtered stock imagery are **dropped, not softened**: the only raster a look skill may ask for is a text-free hero plate or hero object with its provenance sidecar (ADR 0222). `stitch-design-taste`'s signature inline headline image is a hero object under that same rule.
27
+ 6. **Every motion rule lives inside the Kill Switch, and what cannot live there is named unavailable.** Scroll-driven motion is CSS (`animation-timeline: view()` / `scroll()`) behind `@supports`, with at most one `IntersectionObserver` adding a single class as the fallback; spring physics, pointer-tracked hover and shared-element transitions are named *not available* rather than approximated in script. Brutalist degradation (halftone, scanlines, noise) is static by construction, built from the one legal literal.
28
+ 7. **The pre-flight is the kit, and the detector is the mechanical half of it.** Each skill closes with a checklist read off `kit/render.js` shots and `kit/contrast.js` pairs, and points at `kit/tells.js` (via `check-mock.js`) for the rules a machine can decide, so a look skill adds no reviewer of its own.
29
+
30
+ ## Consequences
31
+
32
+ - The module now ships **thirteen** in-house skills and the criterion `uidesign-skills-in-house` has its full set of style skills. A builder on any instance can ask for a minimal, a brutalist or an anti-default surface and get a grammar that composes in *that instance's* colours, not in the grammar author's.
33
+ - The four looks are directly comparable, because they differ only in structure: rendering the same page under the same pack with two different look skills shows the grammar, which is what a builder is actually choosing between.
34
+ - `tests/ui_design_skills.mjs` gains a `LOOKS` group that pins what a look skill may not do: name a hex literal of its own outside the legal black/white-with-alpha carve-out, add a face, or mandate an image. The generic in-house pins (the preamble, the `Rebuilt from` section, the style library named, no image mandate, the switch, the kit) already applied and still do.
35
+ - Rejected: shipping each look as a **pack** in the style library instead of a skill (a look skill's content is composition, and three of the four have no palette worth carrying — `gpt-taste` is pack-agnostic and `stitch-design-taste` writes a document); allowing a look skill to declare a sixteenth token for its substrate (a contract change touching every sheet and every drift test, for four skills that do not need it once a radius is understood as a derived tier); and keeping the upstream's random selection behind a fixed seed (still unreadable in a diff, and it would have made the sibling check impossible).
36
+ - Open: `radius: 0` on a brutalist surface is a derived-tier decision written in that sheet's header comment. If a third look wants a systemic derived-tier override, the right answer is a **derived tier in the library's pack shape**, not a third comment convention — that would be its own ADR.
@@ -315,6 +315,7 @@ This keeps the decision history honest and traceable.
315
315
  | 0227 | [**A task network map is refused; the goal graph is the map, and search answers findability** ([task 1003282](https://cloudbongos.com/builders#/task/1003282) · goal 1000072, criterion `legibility-project-map`, which gates itself on this spike). Measured across a swept density range (p=2%–40% of tasks carrying a dependency): a node-link view of ~1,357 tasks is confetti, not structure, and densifying it draws forty goals badly while claiming to show a thousand tasks — a confident picture of nothing is the opposite of the legibility this goal serves. Decision: NO whole-corpus task map at any density; the readable surface is the ~40-node GOAL graph as the entry point with a per-goal DEPENDENCY FOREST as the drill-down, queried when a goal is opened rather than zoomed out of a global map. Every edge a map could draw already exists in the DB and none needs a new table — `task_dependencies` (020), `tasks.parent_task_id`, `tasks.goal_id`, `task_criteria`→`done_when_criteria`, `idea_inbox.promoted_to_task_id`, `idea_inbox.merged_into_idea_id` (`core_195`), `tasks.version_id` (membership, never an edge). **Findability (goal 1000027) answers the owner’s question more cheaply than a map**: the ask splits into “find what I was brainstorming”, which `/recall` (ADR 0060) plus the two lineage columns already answers end to end and which wants a text LINEAGE TRAIL — one thing and its ancestry — not a picture; and “see the shape of the portfolio”, the only half a graph earns, which is about ~40 goals and not about tasks. So the trail outranks the map and is sequenced first. Accessibility: the TABLE is the primary surface and the graph the enhancement (not an `aria-label` on an SVG blob, not a toggle hiding the accessible path), no sideways scroll on the page (the graph scrolls inside its own container), and category is text as well as colour since the ADR 0192 set is not colour-distinguishable at forty nodes. Ranked list: (1) measure the real density against the live DB — it GATES and may cancel the rest, (2) the lineage trail, (3) the goal graph, (4) the per-goal forest. Rejected: view A (every task); view D (densified); a prototype as the output (the criterion forbade it — `spike-task-map.js` is a measuring instrument under `docs/research/`, wired to no route); and building before measuring. Honest limit: the corpus is SYNTHETIC (the live DB was unreachable), so the verdict is robust across the sweep but the specific numbers are model output — which is why item 1 is a measurement against the real DB.](<redacted>.md) | GDS / legibility + hall |
316
316
  | 0228 | [**The reading room owes a reference its content rules, not a second archetype** ([task 1003473](https://cloudbongos.com/builders#/task/1003473) · goal 1000081). The archetype task 1003306 built for the primer — a linear read with a gate — now serves drachmae, a REFERENCE people open to answer one question about how they get paid. Decision: the same room with ONE body modifier, `room--reference`, switching on content rules in `room.css` §8 rather than a second sheet or a `.page-head--reference` voice: the linear-read instruments are off (no progress hairline, no section counters, no read time; `primer.css`, which holds only the acknowledge gate, is no longer loaded), the outline goes to h3 depth read from the rendered DOM and lights the entry and its part, every h2/h3/h4 is an always-visible address (`.room-anchor`) that copies its link, a deep link is landed by the page after the document, the live section and the fonts (a swap moved the browser's own landing 300px, and `:target` had resolved against nothing), the collapsed phone outline rides under the top bar naming the part, and the live bounty table is a section ahead of the closing links rather than an appendix after them. Found by rendering before touching anything and fixed in the shared reader: `md-reader.js` stopped at `###`, so the doc's six earning sources rendered as paragraphs with a literal `####`; the bold rule refused an inner `*`; a linked heading slugged its target's path into the address. Rejected: a second archetype sheet, hover-only anchors (a phone has no hover), an accordion outline (the sub-questions are what a reader scans for), placing the live table inside the prose (it would lose its outline entry), and teaching the kit stub to serve markdown (the ui-design module's). Pinned by `tests/hall_reference_world.mjs`, four of whose tests run the reader in a vm.](<redacted>.md) | hall / design |
317
317
  | 0229 | [**The title is the door into a task record, and the record exits to where it was opened from** ([task 1003468](https://cloudbongos.com/builders#/task/1003468) · goal 1000081). The owner, working the live hall: a to-do card "just gets selected", and a record opened from a goal "only offers the tasks page". Both were shipped behaviour: tasks 1759/1869 made multi-select the primary card interaction and left a 26px `--ink-faint` ⤢ glyph as the only way from a claimable card into the record, and `task.js` hardcoded `Open the work board` in three renders with `task.html`'s crumb a fourth. Decision: `.task__title` carries a real link (`.task__link`) on both surfaces that render the card — the convention `.gr-title` and the ledger rows already use — bought up to the 24px floor with the inline-block + padding + equal-negative-margin recipe so the card does not re-space; the card body still toggles selection and bulk claim is untouched; the glyph goes (a second door to the same room, one the owner never found). The link carries WHERE it was opened from as `?from=<path+query+hash>` (`OTBTaskDetail.href`), a query param because the origin must survive a reload and a copied link and because a referrer drops the `#/goal/N` fragment; `task.js` resolves the exit once — `?from=` → same-origin referrer → the work board — points the crumb before the fetch so the way back exists in every state, and labels it the way the sidebar does. A value is honoured only as a path on this host: one leading slash, no backslash, no whitespace, never `/api/`, never this same record. Rejected: opening on the card body (deletes bulk claim), keeping the glyph beside the link, in-memory origin, referrer-first, `history.back()`. Pinned by seven vm tests in `tests/hall_record_world.mjs` §10 and four in `tests/hall_board_world.mjs` §7.](<redacted>.md) | hall / design |
318
+ | 0230 | [**A look skill is a composition grammar; the palette is the pack and the texture is a library entry** ([task 1003327](https://cloudbongos.com/builders#/task/1003327) · goal 1000083, criterion `uidesign-skills-in-house`). Four groups of the taste-skill rebuild spec ship a *look*, not a method, and upstream each one shipped a palette and a set of faces — which is the one thing the fifteen-token contract forbids (ADR 0196, 0219). Decisions: (1) a look skill ships **structure, rhythm, type roles, component anatomy, motion and bans, and no colours** — every colour a `var()` or `color-mix()` of the fifteen, the palette the instance's pack, the texture a named entry in `modules/ui-design/styles/`, and no skill adds a face. (2) The brutalist "one substrate per project" becomes an **archetype** deciding which mode the surface is composed *for*, while the other mode ships complete and measured; "never mixed in one interface" is the part that was about craft. (3) `gpt-taste`'s prompt-seeded **random** selection becomes a deterministic one derived from the route and bumped against sibling surfaces, written into a plan block before any markup with the hero arithmetic, the grid-density proof and the measured contrast pairs — a roll nobody can reproduce is not a decision. (4) `stitch-design-taste` **transcribes** the world instead of authoring one: the platform's own `DESIGN.md` frontmatter shape, the thirteen diffed from the pack rather than retyped, and its universal bans stated as defaults the instance overrules. (5) The upstream's seeded placeholder photography is **dropped, not softened** (ADR 0222); (6) motion is CSS inside the Kill Switch and what cannot live there is named *not available*; (7) the pre-flight is the kit and `tells.js` is its mechanical half, so a look skill adds no reviewer of its own. Rejected: shipping each look as a pack, a sixteenth token for a substrate, a fixed seed behind the same roll.](<redacted>.md) | ui-design / skills |
318
319
  | 0226 | [**One stale-claim timer; reporting degrades where enforcement refuses** ([task 1003476](https://cloudbongos.com/builders#/task/1003476), goal 1000072, criterion `legibility-sort-and-staleness`). "How long may a claim go silent" had FOUR answers and none of them was the project's: the sweeper that actually releases a claim read `GDS_STALE_CLAIM_HOURS` (else 6h); `GET /builders/roster` and `GET /builders/:id/active-claims` each hardcoded 24h in byte-identical blocks; and the two `session_pulses` helpers defaulted to 30 minutes. The 6-vs-24 pair is the harm: the roster is the screen an Archon opens to decide whether to intervene, and for **eighteen hours** after the sweeper had released a claim, stamped its session log `[auto-released:stale]` and returned the task to `ready`, that screen still showed it healthy — while the roster's own comment claimed to "mirror" the sweeper, true of the definition and false of the number. Decision: ONE resolver, `src/stale-timer.js` (a KERNEL file, the `instance-config.js`/`branding.js` category — host config a module reads, never hardcodes), reached by modules through the doorway and by core routes and the CLI directly. Precedence: explicit override (`--threshold-hours`, `?stale_hours=` — a LENS, labelled `query`, never a reconfiguration) → `<PREFIX>_STALE_CLAIM_HOURS` via `instance-config.resolveEnv`, whose legacy prefix chain still honours the live `GDS_STALE_CLAIM_HOURS` so **nothing in a running deployment has to change** (and which is the channel ADR 0190's runner already patches into `web.env`) → **6**, the SWEEP's historical number and deliberately not the roster's 24, because the sweep is the surface that acts and unifying on 24 would have made every project three times more patient with a dead claim under cover of a refactor. Bound 1..720h — the range `/builders/roster` has published since V3.R14; one timer, one bound. Every surface that prints the timer prints its PROVENANCE (`stale_hours_source`, the sweep header, the auto-release note): a number without it is exactly what let 6 and 24 coexist unnoticed. **The fail posture is asymmetric and that is the decision**: the resolver reports an unusable value rather than throwing, then a surface that only READS degrades to the default and names the bad var (500-ing the roster an Archon opened to find the problem would hide the problem), while the SWEEP refuses to run at all (it releases other people's claims and stamps their logs; no reload undoes that) — a surface that only reads may guess and say so, a surface that acts may not guess. Both routes now share one `staleHoursFor(req, res)`; two copies of a literal is how the drift happened twice inside one file. Rejected: a new `config/stale.json` tier (the env route already IS the per-project channel); making 24 the shared default; throwing from the resolver (forces a second reader — the original bug); folding in the boards' 14/30/60-DAY task buckets (a different question — days, about a task, a browsing lens with no enforcement behind it); a DB row + settings UI (a reasonable next step, but the defect was four numbers, not a missing knob — a row added before the readers agreed would have been a fifth).](<redacted>.md) | GDS / claims + ops |
319
320
 
320
321
  > ⚠️ **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.