@bongos/core 1.19.816 → 1.19.818
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 +56 -41
- package/.claude/skills/worktree-clean/SKILL.md +3 -2
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +6 -0
- package/clients/bongos-client/index.cjs +6 -0
- package/clients/bongos-client/index.d.ts +9 -0
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/adr/0298-the-reader-lens-is-advisory-and-waits-on-a-voice-guide.md +121 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +178 -3
- package/docs/api-reference.md +5 -2
- package/docs/copy-inventory.md +41 -38
- package/docs/copy-registry.json +67 -40
- package/docs/module-api-changelog.md +4 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +6 -0
- package/modules/government/catalog.js +1 -1
- package/modules/hall-ui/public/settings-specialities.js +56 -2
- package/modules/hall-ui/public/settings.html +1 -0
- package/modules/lifecycle/cascade.js +18 -5
- package/modules/lifecycle/routes/task-route-helpers.js +50 -3
- package/modules/lifecycle/tests/cascade.mjs +11 -1
- package/modules/specialities/db.js +41 -2
- package/modules/specialities/migrations/specialities_002_offered.sql +57 -0
- package/modules/specialities/routes/specialities.js +64 -0
- package/modules/specialities/specialities.js +30 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/category-advisory-guard.js +49 -8
- package/scripts/gds/linkify-refs.js +9 -1
- package/scripts/gds/run-unit-tests.js +8 -1
- package/scripts/gds/stale-worktrees.js +50 -6
- package/src/module-api.js +1 -1
- package/tests/government_require_permission.mjs +90 -14
- package/tests/linkify_refs.mjs +17 -0
- package/tests/migration_allocation.mjs +70 -0
- package/tests/speciality_offered.mjs +212 -0
- package/tests/stale_worktrees.mjs +54 -0
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.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.818",
|
|
6
|
+
"core_contract": "1.19.818",
|
|
7
|
+
"source_commit": "7f98428f5e6532100482d729716d92638bee2eb5",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-17T08:
|
|
9
|
+
"built_at": "2026-09-17T08:43:53.963Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 490,
|
|
13
13
|
"agent_docs_stubbed": 26,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2217,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2733,
|
|
20
|
+
"tree_sha256": "35b8712820d4287686e4a01a9a497c386fd32f24a5109b691a39892d4aeaa964",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
{
|
|
253
253
|
"path": ".claude/skills/worktree-clean/SKILL.md",
|
|
254
254
|
"mode": "0000644",
|
|
255
|
-
"sha256": "
|
|
255
|
+
"sha256": "6548fe1de89c6909def02b76f022cae739c5b129d179a63538b9a1ab252e5030"
|
|
256
256
|
},
|
|
257
257
|
{
|
|
258
258
|
"path": ".devcontainer/Dockerfile",
|
|
@@ -347,12 +347,12 @@
|
|
|
347
347
|
{
|
|
348
348
|
"path": "clients/bongos-client/README.md",
|
|
349
349
|
"mode": "0000644",
|
|
350
|
-
"sha256": "
|
|
350
|
+
"sha256": "3db2ef5abdfe42a0e950339728759742ac017fdbcae1ed1b8e8b00798773df09"
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
353
|
"path": "clients/bongos-client/bongos-client.global.js",
|
|
354
354
|
"mode": "0000644",
|
|
355
|
-
"sha256": "
|
|
355
|
+
"sha256": "cd6c84faa0f4d65498108d2681fff1b7089c6ee80212af6d7bf29c5d29c77ee1"
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"path": "clients/bongos-client/examples/hello-world.mjs",
|
|
@@ -362,17 +362,17 @@
|
|
|
362
362
|
{
|
|
363
363
|
"path": "clients/bongos-client/index.cjs",
|
|
364
364
|
"mode": "0000644",
|
|
365
|
-
"sha256": "
|
|
365
|
+
"sha256": "0b9c1a362adc59ce61f6b0b6f92f47103f6060810cbcf90ee87391b255a1d96f"
|
|
366
366
|
},
|
|
367
367
|
{
|
|
368
368
|
"path": "clients/bongos-client/index.d.ts",
|
|
369
369
|
"mode": "0000644",
|
|
370
|
-
"sha256": "
|
|
370
|
+
"sha256": "d2b1b59658899d95484cea739fad158009c1d5365881854b117e8350e09521d3"
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
"path": "clients/bongos-client/index.mjs",
|
|
374
374
|
"mode": "0000644",
|
|
375
|
-
"sha256": "
|
|
375
|
+
"sha256": "9cf6c38c64ba9a7f753ba393daddd7c3f76e246f34b713130eb81e77973e23de"
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"path": "clients/bongos-client/package.json",
|
|
@@ -1974,20 +1974,25 @@
|
|
|
1974
1974
|
"mode": "0000644",
|
|
1975
1975
|
"sha256": "4e6d5268c58e905c86acc1bbd4c66778e3695ecd37cbc1c9e0f1448cd67f26a9"
|
|
1976
1976
|
},
|
|
1977
|
+
{
|
|
1978
|
+
"path": "docs/adr/0298-the-reader-lens-is-advisory-and-waits-on-a-voice-guide.md",
|
|
1979
|
+
"mode": "0000644",
|
|
1980
|
+
"sha256": "8fcac086f276e57b59ba635cdf34600bf78bfb69d80177d43065dfc6776b0611"
|
|
1981
|
+
},
|
|
1977
1982
|
{
|
|
1978
1983
|
"path": "docs/adr/README.md",
|
|
1979
1984
|
"mode": "0000644",
|
|
1980
|
-
"sha256": "
|
|
1985
|
+
"sha256": "14c4e2e04bba4a0438375364a88e41eca44983ab0fb2c3ecd13bf0190f0ad151"
|
|
1981
1986
|
},
|
|
1982
1987
|
{
|
|
1983
1988
|
"path": "docs/api-reference.md",
|
|
1984
1989
|
"mode": "0000644",
|
|
1985
|
-
"sha256": "
|
|
1990
|
+
"sha256": "74c345407b073635a4b9eaa54b72a92e543a1d4e9a893b0a3c688ef32bdc86b0"
|
|
1986
1991
|
},
|
|
1987
1992
|
{
|
|
1988
1993
|
"path": "docs/api/openapi.json",
|
|
1989
1994
|
"mode": "0000644",
|
|
1990
|
-
"sha256": "
|
|
1995
|
+
"sha256": "28a4aec3929aefa72cfdffc1bcad6eba5ce1d3bb00518e28eddee631f219dfe5"
|
|
1991
1996
|
},
|
|
1992
1997
|
{
|
|
1993
1998
|
"path": "docs/architecture.md",
|
|
@@ -2012,12 +2017,12 @@
|
|
|
2012
2017
|
{
|
|
2013
2018
|
"path": "docs/copy-inventory.md",
|
|
2014
2019
|
"mode": "0000644",
|
|
2015
|
-
"sha256": "
|
|
2020
|
+
"sha256": "4e21dfe9140f8da88b5ba49d7d2c380196408073253e915198ab5f9cdbeab933"
|
|
2016
2021
|
},
|
|
2017
2022
|
{
|
|
2018
2023
|
"path": "docs/copy-registry.json",
|
|
2019
2024
|
"mode": "0000644",
|
|
2020
|
-
"sha256": "
|
|
2025
|
+
"sha256": "cb8da77e04f8fa238c513bf2fc04f4f00a13527022e2fbb34dd607ddced16bdd"
|
|
2021
2026
|
},
|
|
2022
2027
|
{
|
|
2023
2028
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2542,7 +2547,7 @@
|
|
|
2542
2547
|
{
|
|
2543
2548
|
"path": "docs/module-api-changelog.md",
|
|
2544
2549
|
"mode": "0000644",
|
|
2545
|
-
"sha256": "
|
|
2550
|
+
"sha256": "0b561d6587c66805edf357a97265aa313ab4cf1610e23c63efbb30fc0f1fdf78"
|
|
2546
2551
|
},
|
|
2547
2552
|
{
|
|
2548
2553
|
"path": "docs/modules-contract.md",
|
|
@@ -4077,7 +4082,7 @@
|
|
|
4077
4082
|
{
|
|
4078
4083
|
"path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
|
|
4079
4084
|
"mode": "0000644",
|
|
4080
|
-
"sha256": "
|
|
4085
|
+
"sha256": "0b9c1a362adc59ce61f6b0b6f92f47103f6060810cbcf90ee87391b255a1d96f"
|
|
4081
4086
|
},
|
|
4082
4087
|
{
|
|
4083
4088
|
"path": "modules/dev-box/app/test/unit.mjs",
|
|
@@ -4327,7 +4332,7 @@
|
|
|
4327
4332
|
{
|
|
4328
4333
|
"path": "modules/government/catalog.js",
|
|
4329
4334
|
"mode": "0000644",
|
|
4330
|
-
"sha256": "
|
|
4335
|
+
"sha256": "da48187e485a7528bdd705c49df7a28c4ce6a3aad3c2885589f06dd4c8214840"
|
|
4331
4336
|
},
|
|
4332
4337
|
{
|
|
4333
4338
|
"path": "modules/government/config.js",
|
|
@@ -5257,7 +5262,7 @@
|
|
|
5257
5262
|
{
|
|
5258
5263
|
"path": "modules/hall-ui/public/settings-specialities.js",
|
|
5259
5264
|
"mode": "0000644",
|
|
5260
|
-
"sha256": "
|
|
5265
|
+
"sha256": "384aa465d951e97d8d3e2b7633eff49d1d82e63bdd63baf0b38cf81482c4716d"
|
|
5261
5266
|
},
|
|
5262
5267
|
{
|
|
5263
5268
|
"path": "modules/hall-ui/public/settings.css",
|
|
@@ -5267,7 +5272,7 @@
|
|
|
5267
5272
|
{
|
|
5268
5273
|
"path": "modules/hall-ui/public/settings.html",
|
|
5269
5274
|
"mode": "0000644",
|
|
5270
|
-
"sha256": "
|
|
5275
|
+
"sha256": "4bea1273047e2fbb90f76f01892cb82da7aeaa1417f91a267249512a5e216993"
|
|
5271
5276
|
},
|
|
5272
5277
|
{
|
|
5273
5278
|
"path": "modules/hall-ui/public/settings.js",
|
|
@@ -5497,7 +5502,7 @@
|
|
|
5497
5502
|
{
|
|
5498
5503
|
"path": "modules/lifecycle/cascade.js",
|
|
5499
5504
|
"mode": "0000644",
|
|
5500
|
-
"sha256": "
|
|
5505
|
+
"sha256": "acc9cf557aabc3fe10efc8c7272162cf288428e8077a24f5df06648e30881337"
|
|
5501
5506
|
},
|
|
5502
5507
|
{
|
|
5503
5508
|
"path": "modules/lifecycle/claim-eligibility.js",
|
|
@@ -5842,7 +5847,7 @@
|
|
|
5842
5847
|
{
|
|
5843
5848
|
"path": "modules/lifecycle/routes/task-route-helpers.js",
|
|
5844
5849
|
"mode": "0000644",
|
|
5845
|
-
"sha256": "
|
|
5850
|
+
"sha256": "c82bfa19da18a2b952ad4e2a0311ef983050fd0a4c8a095c8fb3f3581f3a4801"
|
|
5846
5851
|
},
|
|
5847
5852
|
{
|
|
5848
5853
|
"path": "modules/lifecycle/routes/task-write-routes.js",
|
|
@@ -5917,7 +5922,7 @@
|
|
|
5917
5922
|
{
|
|
5918
5923
|
"path": "modules/lifecycle/tests/cascade.mjs",
|
|
5919
5924
|
"mode": "0000644",
|
|
5920
|
-
"sha256": "
|
|
5925
|
+
"sha256": "0734ad734ac5ef05c86fa81493c12fed08ffe421781d9ceeebe413c876bf9cf1"
|
|
5921
5926
|
},
|
|
5922
5927
|
{
|
|
5923
5928
|
"path": "modules/lifecycle/version-autoclose.js",
|
|
@@ -7297,13 +7302,18 @@
|
|
|
7297
7302
|
{
|
|
7298
7303
|
"path": "modules/specialities/db.js",
|
|
7299
7304
|
"mode": "0000644",
|
|
7300
|
-
"sha256": "
|
|
7305
|
+
"sha256": "3e060dfa1aa11f4ca6c1949bb36599e24c33cfca6ba983c1ce740de67f6e1152"
|
|
7301
7306
|
},
|
|
7302
7307
|
{
|
|
7303
7308
|
"path": "modules/specialities/migrations/specialities_001_specialities.sql",
|
|
7304
7309
|
"mode": "0000644",
|
|
7305
7310
|
"sha256": "055210da2726c1d17457900a9b44566c58f371b3206365c5352474114be57251"
|
|
7306
7311
|
},
|
|
7312
|
+
{
|
|
7313
|
+
"path": "modules/specialities/migrations/specialities_002_offered.sql",
|
|
7314
|
+
"mode": "0000644",
|
|
7315
|
+
"sha256": "5d2c6a648b0a7eb85893c2a3302af721206cc0ca0f58420cb4281e427b86de7a"
|
|
7316
|
+
},
|
|
7307
7317
|
{
|
|
7308
7318
|
"path": "modules/specialities/module.json",
|
|
7309
7319
|
"mode": "0000644",
|
|
@@ -7312,12 +7322,12 @@
|
|
|
7312
7322
|
{
|
|
7313
7323
|
"path": "modules/specialities/routes/specialities.js",
|
|
7314
7324
|
"mode": "0000644",
|
|
7315
|
-
"sha256": "
|
|
7325
|
+
"sha256": "132b28199202c742045c17bd930889d1a3327af1b17445d45d592bfc472bed76"
|
|
7316
7326
|
},
|
|
7317
7327
|
{
|
|
7318
7328
|
"path": "modules/specialities/specialities.js",
|
|
7319
7329
|
"mode": "0000644",
|
|
7320
|
-
"sha256": "
|
|
7330
|
+
"sha256": "413477a716f3a60abc0763bccfb10a593c4eb19301131de0230eb3d72ffee299"
|
|
7321
7331
|
},
|
|
7322
7332
|
{
|
|
7323
7333
|
"path": "modules/status-ui/CLAUDE.md",
|
|
@@ -7792,12 +7802,12 @@
|
|
|
7792
7802
|
{
|
|
7793
7803
|
"path": "package-lock.json",
|
|
7794
7804
|
"mode": "0000644",
|
|
7795
|
-
"sha256": "
|
|
7805
|
+
"sha256": "c314948249345b2ef9e9c43e7dc32287f3901882cbc0c4d51a475d568ed0fb76"
|
|
7796
7806
|
},
|
|
7797
7807
|
{
|
|
7798
7808
|
"path": "package.json",
|
|
7799
7809
|
"mode": "0000644",
|
|
7800
|
-
"sha256": "
|
|
7810
|
+
"sha256": "8be1abd0cb53633278698edda8b8b78edf57224e89eb3b08806ede49014dab6d"
|
|
7801
7811
|
},
|
|
7802
7812
|
{
|
|
7803
7813
|
"path": "public-docs/index.html",
|
|
@@ -8062,7 +8072,7 @@
|
|
|
8062
8072
|
{
|
|
8063
8073
|
"path": "scripts/gds/category-advisory-guard.js",
|
|
8064
8074
|
"mode": "0000644",
|
|
8065
|
-
"sha256": "
|
|
8075
|
+
"sha256": "a71ac076299b9e37bf8e0a6ff8761f8ba3059271b2596b6ee8941fc24533357d"
|
|
8066
8076
|
},
|
|
8067
8077
|
{
|
|
8068
8078
|
"path": "scripts/gds/cf-tunnel.js",
|
|
@@ -8507,7 +8517,7 @@
|
|
|
8507
8517
|
{
|
|
8508
8518
|
"path": "scripts/gds/linkify-refs.js",
|
|
8509
8519
|
"mode": "0000644",
|
|
8510
|
-
"sha256": "
|
|
8520
|
+
"sha256": "16e9c92e2466f92de1339eac911193807678c4c7d2c6b837ecd1195c102ebf56"
|
|
8511
8521
|
},
|
|
8512
8522
|
{
|
|
8513
8523
|
"path": "scripts/gds/lint-infra-exec.js",
|
|
@@ -8822,7 +8832,7 @@
|
|
|
8822
8832
|
{
|
|
8823
8833
|
"path": "scripts/gds/run-unit-tests.js",
|
|
8824
8834
|
"mode": "0000644",
|
|
8825
|
-
"sha256": "
|
|
8835
|
+
"sha256": "be80f6ea38abdbc71f5f718b51db9a54b931745859e885ea1a97ff9465a81596"
|
|
8826
8836
|
},
|
|
8827
8837
|
{
|
|
8828
8838
|
"path": "scripts/gds/sandbox-stage.js",
|
|
@@ -9182,7 +9192,7 @@
|
|
|
9182
9192
|
{
|
|
9183
9193
|
"path": "scripts/gds/stale-worktrees.js",
|
|
9184
9194
|
"mode": "0000644",
|
|
9185
|
-
"sha256": "
|
|
9195
|
+
"sha256": "9f6ce80e5325f4cfe68cfa6cb82bec52d594af7e461b6734724819b23cbb0d37"
|
|
9186
9196
|
},
|
|
9187
9197
|
{
|
|
9188
9198
|
"path": "scripts/gds/start.js",
|
|
@@ -9687,7 +9697,7 @@
|
|
|
9687
9697
|
{
|
|
9688
9698
|
"path": "src/module-api.js",
|
|
9689
9699
|
"mode": "0000644",
|
|
9690
|
-
"sha256": "
|
|
9700
|
+
"sha256": "d26e3a559beac4c6431a5cf5476c7a0976798ec8b9174814c06f7d64fd1f6f91"
|
|
9691
9701
|
},
|
|
9692
9702
|
{
|
|
9693
9703
|
"path": "src/module-loader/catalog.js",
|
|
@@ -11287,7 +11297,7 @@
|
|
|
11287
11297
|
{
|
|
11288
11298
|
"path": "tests/government_require_permission.mjs",
|
|
11289
11299
|
"mode": "0000644",
|
|
11290
|
-
"sha256": "
|
|
11300
|
+
"sha256": "95a5215153c5d98f4fe9ecd3d36ca1ce76d9c486abef8f69dfca0ce3d5cfb006"
|
|
11291
11301
|
},
|
|
11292
11302
|
{
|
|
11293
11303
|
"path": "tests/government_resolver.mjs",
|
|
@@ -11862,7 +11872,7 @@
|
|
|
11862
11872
|
{
|
|
11863
11873
|
"path": "tests/linkify_refs.mjs",
|
|
11864
11874
|
"mode": "0000644",
|
|
11865
|
-
"sha256": "
|
|
11875
|
+
"sha256": "d072512abdd464716a6880a528da08bc3abb06fd7c69d59d075a699c665229a8"
|
|
11866
11876
|
},
|
|
11867
11877
|
{
|
|
11868
11878
|
"path": "tests/live_channel.mjs",
|
|
@@ -11977,7 +11987,7 @@
|
|
|
11977
11987
|
{
|
|
11978
11988
|
"path": "tests/migration_allocation.mjs",
|
|
11979
11989
|
"mode": "0000644",
|
|
11980
|
-
"sha256": "
|
|
11990
|
+
"sha256": "adc1a84f0b251a99471bd4f14367d949432476b0d504bff4de3ae0167eadfb30"
|
|
11981
11991
|
},
|
|
11982
11992
|
{
|
|
11983
11993
|
"path": "tests/migration_namespace.mjs",
|
|
@@ -13239,6 +13249,11 @@
|
|
|
13239
13249
|
"mode": "0000644",
|
|
13240
13250
|
"sha256": "9de6fbffd858190096bc22d556ccae101a6206adeee05bb146bd2a0a1a59d15c"
|
|
13241
13251
|
},
|
|
13252
|
+
{
|
|
13253
|
+
"path": "tests/speciality_offered.mjs",
|
|
13254
|
+
"mode": "0000644",
|
|
13255
|
+
"sha256": "13d7be30c41855ac4a39689bc88ea2be2c896ca071b884bbd0e81cc9c29bc180"
|
|
13256
|
+
},
|
|
13242
13257
|
{
|
|
13243
13258
|
"path": "tests/spike_task_map.mjs",
|
|
13244
13259
|
"mode": "0000644",
|
|
@@ -13267,7 +13282,7 @@
|
|
|
13267
13282
|
{
|
|
13268
13283
|
"path": "tests/stale_worktrees.mjs",
|
|
13269
13284
|
"mode": "0000644",
|
|
13270
|
-
"sha256": "
|
|
13285
|
+
"sha256": "3cc48273341fe8e71ba928ec7c474533d510b74d5b107cad6e3af278219ccd41"
|
|
13271
13286
|
},
|
|
13272
13287
|
{
|
|
13273
13288
|
"path": "tests/start_env_guard.mjs",
|
|
@@ -8,8 +8,9 @@ description: >-
|
|
|
8
8
|
|
|
9
9
|
## What this skill does
|
|
10
10
|
|
|
11
|
-
1. `node scripts/gds/stale-worktrees.js` — the list. A worktree is **stale** when its branch is an ancestor of `origin/main` (the land happened) or the branch is gone (the ship deleted it). Detached worktrees
|
|
12
|
-
2. Show the stale list to the builder (names + why).
|
|
11
|
+
1. `node scripts/gds/stale-worktrees.js` — the list. A worktree is **stale** when its branch is an ancestor of `origin/main` (the land happened) or the branch is gone (the ship deleted it). Detached worktrees, unmerged branches, and branches sitting exactly at `origin/main` (a claim worktree with no commits yet — task 1003912) are **live** and never touched. Run `git fetch origin` first so "merged into main" reflects today's main, not the last fetch. The same call also names **husks** — directories under `.claude/worktrees/` that git does not list as worktrees at all (step 6).
|
|
12
|
+
2. Show the stale list to the builder (names + why). A worktree holding a **live claim** should not appear: an unmerged branch is live, and since task 1003912 so is a branch still sitting exactly at `origin/main` — the window between `worktree.js add` and the builder's first commit, during which a live claim's tree really did read as "merged into main".
|
|
13
|
+
- Do not treat that as a guarantee. This list is derived from git alone, with no knowledge of who holds what, so **if a name on it looks like someone's live claim, ask before removing it.** The assurance this replaced — that a current claim could not possibly be listed — is exactly what would stop an agent double-checking.
|
|
13
14
|
3. For each stale name: `node scripts/gds/worktree.js remove <name>`. That helper unlinks any node_modules junction BEFORE `git worktree remove`, which is the whole reason raw git is off-limits here (learning in `scripts/gds/CLAUDE.md` → "Gotchas / invariants"; the `git-guard.js` PreToolUse hook blocks the raw form).
|
|
14
15
|
- A worktree with untracked leftovers (`.playwright-mcp/`, a stray screenshot) refuses without `--force`. Show the `git -C <path> status --porcelain` output; if it is only untracked junk, re-run with `--force`. If it shows **modified tracked files**, skip it and report — someone's uncommitted work is not this skill's to delete.
|
|
15
16
|
4. `git worktree prune` — clears any registrations whose directory is already gone.
|
|
@@ -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
|
-
-
|
|
8
|
+
- 393 operations across 59 resource groups
|
|
9
9
|
|
|
10
10
|
## Use it from your project
|
|
11
11
|
|
|
@@ -857,6 +857,12 @@ function createClient(opts = {}) {
|
|
|
857
857
|
postSpecialitiesIdDocuments: (args) => request("POST", "/specialities/{id}/documents", { hasBody: true }, args),
|
|
858
858
|
// DELETE /specialities/{id}/documents/{docId} — rank: any-builder — DELETE /specialities/:id/documents/:docId
|
|
859
859
|
deleteSpecialitiesIdDocumentsDocId: (args) => request("DELETE", "/specialities/{id}/documents/{docId}", { hasBody: false }, args),
|
|
860
|
+
// POST /specialities/{id}/offer — rank: metic+archon — POST /specialities/:id/offer
|
|
861
|
+
postSpecialitiesIdOffer: (args) => request("POST", "/specialities/{id}/offer", { hasBody: true }, args),
|
|
862
|
+
// POST /specialities/{id}/unoffer — rank: metic+archon — POST /specialities/:id/unoffer
|
|
863
|
+
postSpecialitiesIdUnoffer: (args) => request("POST", "/specialities/{id}/unoffer", { hasBody: true }, args),
|
|
864
|
+
// GET /specialities/offered — rank: any-builder — GET /specialities/offered
|
|
865
|
+
getSpecialitiesOffered: (args) => request("GET", "/specialities/offered", { hasBody: false }, args),
|
|
860
866
|
},
|
|
861
867
|
"sso": {
|
|
862
868
|
// POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
|
|
@@ -856,6 +856,12 @@ function createClient(opts = {}) {
|
|
|
856
856
|
postSpecialitiesIdDocuments: (args) => request("POST", "/specialities/{id}/documents", { hasBody: true }, args),
|
|
857
857
|
// DELETE /specialities/{id}/documents/{docId} — rank: any-builder — DELETE /specialities/:id/documents/:docId
|
|
858
858
|
deleteSpecialitiesIdDocumentsDocId: (args) => request("DELETE", "/specialities/{id}/documents/{docId}", { hasBody: false }, args),
|
|
859
|
+
// POST /specialities/{id}/offer — rank: metic+archon — POST /specialities/:id/offer
|
|
860
|
+
postSpecialitiesIdOffer: (args) => request("POST", "/specialities/{id}/offer", { hasBody: true }, args),
|
|
861
|
+
// POST /specialities/{id}/unoffer — rank: metic+archon — POST /specialities/:id/unoffer
|
|
862
|
+
postSpecialitiesIdUnoffer: (args) => request("POST", "/specialities/{id}/unoffer", { hasBody: true }, args),
|
|
863
|
+
// GET /specialities/offered — rank: any-builder — GET /specialities/offered
|
|
864
|
+
getSpecialitiesOffered: (args) => request("GET", "/specialities/offered", { hasBody: false }, args),
|
|
859
865
|
},
|
|
860
866
|
"sso": {
|
|
861
867
|
// POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
|
|
@@ -137,6 +137,7 @@ export interface GetSessionsMineResponse { sessions: unknown; count: unknown }
|
|
|
137
137
|
export interface GetSessionsSearchResponse { sessions: unknown; count: unknown; total: unknown; totals: unknown; limit: unknown; offset: unknown }
|
|
138
138
|
export interface GetSpecialitiesIdDocumentsResponse { documents: unknown }
|
|
139
139
|
export interface GetSpecialitiesIdResponse { speciality: unknown }
|
|
140
|
+
export interface GetSpecialitiesOfferedResponse { suggestions: unknown }
|
|
140
141
|
export interface GetSpecialitiesResponse { specialities: unknown }
|
|
141
142
|
export interface GetSsoPubkeyResponse { alg: unknown; format: unknown; public_key_b64: unknown }
|
|
142
143
|
export interface GetTaskRecommendationsForMeResponse { recommendations: unknown; count: unknown }
|
|
@@ -385,6 +386,8 @@ export interface PostSpecialitiesIdAbandonResponse { ok: boolean; was_active: un
|
|
|
385
386
|
export interface PostSpecialitiesIdAdoptResponse { adoption: unknown }
|
|
386
387
|
export interface PostSpecialitiesIdDocumentsRequest { title: string; body_md: string; source?: string }
|
|
387
388
|
export interface PostSpecialitiesIdDocumentsResponse { skipped?: boolean; reason?: unknown; document?: unknown }
|
|
389
|
+
export interface PostSpecialitiesIdOfferResponse { speciality: unknown }
|
|
390
|
+
export interface PostSpecialitiesIdUnofferResponse { speciality: unknown }
|
|
388
391
|
export interface PostSpecialitiesRequest { name: string; discipline: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean }
|
|
389
392
|
export interface PostSpecialitiesResponse { speciality: unknown }
|
|
390
393
|
export interface PostSsoActivityRollupRequest { client_id: string; client_secret: string; github_id: StringifiableId; credits?: number; tasks_shipped?: number; karma?: number; rank?: string; disciplines?: unknown; recent_ships?: unknown }
|
|
@@ -1219,6 +1222,12 @@ export interface BongosClient {
|
|
|
1219
1222
|
postSpecialitiesIdDocuments(args: RequestArgs & { body: PostSpecialitiesIdDocumentsRequest }): Promise<PostSpecialitiesIdDocumentsResponse>;
|
|
1220
1223
|
/** DELETE /specialities/{id}/documents/{docId} — rank: any-builder */
|
|
1221
1224
|
deleteSpecialitiesIdDocumentsDocId(args?: RequestArgs): Promise<DeleteSpecialitiesIdDocumentsDocIdResponse>;
|
|
1225
|
+
/** POST /specialities/{id}/offer — rank: metic+archon */
|
|
1226
|
+
postSpecialitiesIdOffer(args?: RequestArgs): Promise<PostSpecialitiesIdOfferResponse>;
|
|
1227
|
+
/** POST /specialities/{id}/unoffer — rank: metic+archon */
|
|
1228
|
+
postSpecialitiesIdUnoffer(args?: RequestArgs): Promise<PostSpecialitiesIdUnofferResponse>;
|
|
1229
|
+
/** GET /specialities/offered — rank: any-builder */
|
|
1230
|
+
getSpecialitiesOffered(args?: RequestArgs): Promise<GetSpecialitiesOfferedResponse>;
|
|
1222
1231
|
};
|
|
1223
1232
|
"sso": {
|
|
1224
1233
|
/** POST /sso/activity/rollup — rank: public */
|
|
@@ -853,6 +853,12 @@ export function createClient(opts = {}) {
|
|
|
853
853
|
postSpecialitiesIdDocuments: (args) => request("POST", "/specialities/{id}/documents", { hasBody: true }, args),
|
|
854
854
|
// DELETE /specialities/{id}/documents/{docId} — rank: any-builder — DELETE /specialities/:id/documents/:docId
|
|
855
855
|
deleteSpecialitiesIdDocumentsDocId: (args) => request("DELETE", "/specialities/{id}/documents/{docId}", { hasBody: false }, args),
|
|
856
|
+
// POST /specialities/{id}/offer — rank: metic+archon — POST /specialities/:id/offer
|
|
857
|
+
postSpecialitiesIdOffer: (args) => request("POST", "/specialities/{id}/offer", { hasBody: true }, args),
|
|
858
|
+
// POST /specialities/{id}/unoffer — rank: metic+archon — POST /specialities/:id/unoffer
|
|
859
|
+
postSpecialitiesIdUnoffer: (args) => request("POST", "/specialities/{id}/unoffer", { hasBody: true }, args),
|
|
860
|
+
// GET /specialities/offered — rank: any-builder — GET /specialities/offered
|
|
861
|
+
getSpecialitiesOffered: (args) => request("GET", "/specialities/offered", { hasBody: false }, args),
|
|
856
862
|
},
|
|
857
863
|
"sso": {
|
|
858
864
|
// POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# ADR 0298 — The grader gets a reader lens: advisory, scoped to copy-bearing diffs, and it waits on a written voice
|
|
2
|
+
|
|
3
|
+
**Status:** accepted · **Date:** 2026-09-17 · **Task:** [task 1003937](https://cloudbongos.com/builders#/task/1003937) (goal 1000095 — Working area 6, the artist experience)
|
|
4
|
+
|
|
5
|
+
**Related:** [ADR 0241](0241-the-artist-gate-is-a-per-project-deploy-gate-that-reads-a-state.md) (the artist holds a deploy, never a ship) · [ADR 0242](0242-a-cascade-is-a-declaration-table-on-the-event-that-already-exists.md) (a cascade is a row, not a runner edit) · [ADR 0024](0024-multi-agent-system-architecture.md) (the panel) · [ADR 0233](0233-a-copy-proposal-is-a-task-carrying-a-patch.md) (there is no live CMS)
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Every artist review the cascade files opens with the same instruction:
|
|
10
|
+
|
|
11
|
+
> STEP 1 — REVIEW THE GRADER, not only the work. Read how the grader judged task N's copy
|
|
12
|
+
> and visuals, and coach it: where was it right, and where did it miss what an artist would
|
|
13
|
+
> catch? … this step is the one that compounds.
|
|
14
|
+
|
|
15
|
+
It cannot be followed, and [task 1003937](https://cloudbongos.com/builders#/task/1003937)
|
|
16
|
+
established why across four reviews worked on 2026-09-15 — 1003621 (of
|
|
17
|
+
[task 1003583](https://cloudbongos.com/builders#/task/1003583)), 1003831 (of
|
|
18
|
+
[task 1003761](https://cloudbongos.com/builders#/task/1003761)), 1003833 (of
|
|
19
|
+
[task 1003828](https://cloudbongos.com/builders#/task/1003828)) and 1003836 (of
|
|
20
|
+
[task 1003829](https://cloudbongos.com/builders#/task/1003829)). The grade itself reads back
|
|
21
|
+
fine; `GET /tasks/:id?include=grade` returns scores, verdict, rubric and per-worker notes. The
|
|
22
|
+
problem is what comes back. `modules/grading/grader-rubric.json` v4.0 runs four lenses:
|
|
23
|
+
|
|
24
|
+
| worker | judges |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `narc` | semantic completion — description vs diff |
|
|
27
|
+
| `quality` | code quality (idiom, dead code, tests) + economy |
|
|
28
|
+
| `hacker` | security red-team |
|
|
29
|
+
| `efficiency` | runtime cost, hot paths |
|
|
30
|
+
|
|
31
|
+
None of them reads a sentence for whether it is true, clear, in the project's voice, or worth
|
|
32
|
+
a person's attention. There is no axis an artist can coach. All four graded tasks passed, and
|
|
33
|
+
all four deserved to pass on the axes that were measured — the gate is not too lenient, it is
|
|
34
|
+
not pointed at this.
|
|
35
|
+
|
|
36
|
+
**One partial mechanism already exists, and its limit is the shape of the gap.**
|
|
37
|
+
`modules/grading/grader-prompt.js` injects the craft's written responsibility into the panel
|
|
38
|
+
prompt — *"No slop in the appearance and text of the project; the story, emotion and ideology
|
|
39
|
+
of the project are communicated effectively; project purpose and gravitas are upheld"* — but
|
|
40
|
+
only when `task.discipline === 'artist'`. All four graded tasks were engineer ships. So the
|
|
41
|
+
unjudged case is exactly **copy shipped by someone whose craft is not the copy**, which is
|
|
42
|
+
most of it.
|
|
43
|
+
|
|
44
|
+
## Decision
|
|
45
|
+
|
|
46
|
+
A fifth panel worker — the **reader** — scoring a copy/voice axis. Three things were open;
|
|
47
|
+
the owner settled all three on 2026-09-17.
|
|
48
|
+
|
|
49
|
+
### 1. It runs on copy-bearing diffs only, not on every ship
|
|
50
|
+
|
|
51
|
+
The panel already runs four subagents per ship. A fifth on every ship is a standing spend
|
|
52
|
+
increase on the large majority of ships that change no visible string.
|
|
53
|
+
|
|
54
|
+
The predicate is not new work: `hasCopyOrVisualWork(task)` in `modules/lifecycle/cascade.js`
|
|
55
|
+
already decides, for the artist-review cascade, whether a shipped task put copy or visuals in
|
|
56
|
+
front of a person — `source === 'copy-proposal'`, `discipline === 'artist'`, or a
|
|
57
|
+
`module_key` in the explicit `COPY_VISUAL_MODULES` set. **The reader lens keys off the same
|
|
58
|
+
predicate.** One definition of "this ship is copy-bearing", used by both the after-the-fact
|
|
59
|
+
review and the at-ship lens, so the two can never disagree about what they cover. Widening
|
|
60
|
+
that set widens both at once, deliberately.
|
|
61
|
+
|
|
62
|
+
Where the predicate says no, the panel is exactly what it is today and costs exactly what it
|
|
63
|
+
costs today.
|
|
64
|
+
|
|
65
|
+
### 2. It is advisory — findings, never a verdict
|
|
66
|
+
|
|
67
|
+
The reader records `issues[]` and a `copy_score`. It **cannot** verdict `fail`, and it cannot
|
|
68
|
+
drag the panel to `concerns`.
|
|
69
|
+
|
|
70
|
+
This is not caution, it is [ADR 0241](0241-the-artist-gate-is-a-per-project-deploy-gate-that-reads-a-state.md)
|
|
71
|
+
applied as written. That ADR settled that an artist's judgement may hold a **deploy**, decided
|
|
72
|
+
per project, and never a **builder's ship** — after ADR 0162 retired review gates for stranding
|
|
73
|
+
graded-PASS work. A reader worker that could verdict `fail` would put an artist-shaped
|
|
74
|
+
judgement back on the ship path, which is the precise thing 0241 removed. Gating it would
|
|
75
|
+
require amending 0241 first, and nothing here justifies that.
|
|
76
|
+
|
|
77
|
+
Advisory is also what makes STEP 1 answerable: the artist's review reads the reader's findings
|
|
78
|
+
and coaches *them*, which is a real conversation with a real counterpart, rather than coaching
|
|
79
|
+
four lenses that were never looking.
|
|
80
|
+
|
|
81
|
+
### 3. It waits on a written voice, and does not ship before one exists
|
|
82
|
+
|
|
83
|
+
A copy lens needs a standard to judge against or it is a second model's taste wearing a
|
|
84
|
+
score. The instance's voice is, today, almost entirely unwritten:
|
|
85
|
+
|
|
86
|
+
| source | what it actually carries |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `DESIGN.md` | one hard copy rule — no em/en dash in visible copy, no emoji |
|
|
89
|
+
| `config/branding.neutral.json` | a tagline and a handful of fixed strings |
|
|
90
|
+
| `docs/copy-registry.json` | which 1,860 strings exist — not what good is |
|
|
91
|
+
| `src/role-responsibilities.js` | one sentence, and it only reaches artist-discipline ships |
|
|
92
|
+
|
|
93
|
+
So the build order is fixed: **voice guide first, reader second.** The reader worker is not
|
|
94
|
+
started until the guide is written, and the guide is the artist's own work, not an agent's
|
|
95
|
+
draft of it. A lens built against the four rows above would be recording opinions and calling
|
|
96
|
+
them findings, and that residue would be worse than the silence it replaced — a score nobody
|
|
97
|
+
can appeal to a standard is harder to remove than a missing score.
|
|
98
|
+
|
|
99
|
+
### 4. Until the reader exists, the cascade brief says something an artist can do
|
|
100
|
+
|
|
101
|
+
STEP 1 stays — the instinct behind it is right and this ADR is the proof that it compounds —
|
|
102
|
+
but it stops asking for coaching that has no recipient. In the interim it asks the artist to
|
|
103
|
+
record *where the grade missed what an artist would catch*, naming that the record is the
|
|
104
|
+
evidence this lens is being built from. That is followable today, it produces exactly the
|
|
105
|
+
corpus the voice guide needs, and it converts back into true coaching the moment the reader
|
|
106
|
+
lands.
|
|
107
|
+
|
|
108
|
+
## Consequences
|
|
109
|
+
|
|
110
|
+
- `modules/lifecycle/cascade.js` — STEP 1 rewritten to an instruction that can be carried out,
|
|
111
|
+
pointing at this ADR. No change to the predicate, the trigger, the anti-recursion guard, or
|
|
112
|
+
the fact that the review blocks nothing.
|
|
113
|
+
- Two follow-up tasks are filed at `backlog`, in order, with the dependency edge wired:
|
|
114
|
+
[task 1003976](https://cloudbongos.com/builders#/task/1003976) — the **voice guide** (artist) —
|
|
115
|
+
then [task 1003977](https://cloudbongos.com/builders#/task/1003977) — the **reader worker**
|
|
116
|
+
(engineer, `depends_on` 1003976, so it cannot reach `ready` until the guide ships).
|
|
117
|
+
Neither is started by this ADR.
|
|
118
|
+
- The rubric, the active panel, and every existing worker are untouched. No ship's cost or
|
|
119
|
+
verdict changes as of this decision.
|
|
120
|
+
- If the voice guide is never written, the reader is never built, and STEP 1 is still honest —
|
|
121
|
+
which is the outcome this ADR is careful to leave standing rather than forcing.
|
package/docs/adr/README.md
CHANGED
|
@@ -389,3 +389,4 @@ This keeps the decision history honest and traceable.
|
|
|
389
389
|
| 0295 | [**The registry is the witness the publish lane cannot be** ([task 1003916](https://cloudbongos.com/builders#/task/1003916), goal 1000090). On 2026-09-13 eight publish runs failed over three hours and NOTHING reported it; it was found by a person idly reading the npm version list. Task 1003914 fixed the lossiness and left the silence, which is structural: a failed run is one red row nobody watches, `main` self-heals on the next merge and **erases the evidence**, and the lane's own verdict step writes to a job summary no one reads. Same shape as the nightly upgrade sweep that died reporting `failed=0`. **Decision: a separate reader compares what the lane ANNOUNCED (release commits) against what the registry HOLDS**; the difference is a phantom. The publisher infers from git because OIDC trusted publishing carries no read credential — **that never bound a reader**, and since task 1003872 the package is public, so an anonymous read needs none. Keeping witness and publisher separate IS the point. Daily not hourly (billable minutes, against a failure measured in hours), cadence pinned to the cron by `routine-schedule.js`; deliberately NOT on the session-start path (a third-party call behind a hook timeout). Healthy days are SILENT in Discord — findings to stdout, the all-clear to stderr — because a channel of reassurances stops being read. Two false-alarm sources, each guarded: a closed incident is permanent history (a 3-day window, by TIME not commit count, which a release burst would outrun), and **npm acknowledges a publish before its listing shows it** — found by RUNNING the check, which flagged 1.19.794 fifteen minutes after a publish whose log ended `published @bongos/core@1.19.794` and whose per-version endpoint answered 200; hence a 30-minute grace period plus per-version confirmation, with the listing only ever nominating suspects. A failed read throws rather than reading as "nothing missing". Proven by replaying the REAL outage from git + the live registry, not a synthetic failure. Does NOT detect a lane that stopped being triggered.](0295-the-registry-is-the-witness-the-lane-cannot-be.md) | release / observability |
|
|
390
390
|
| 0296 | [**A role speciality is data over three existing surfaces, not a fourth mechanism** ([task 1003855](https://cloudbongos.com/builders#/task/1003855), goal 1000095). A craft says HOW you work; nothing said what you work ON. A speciality is a named bundle of knowledge, skills and an interaction contract sitting under a craft — an ideator with an Economics speciality. **Decision: it is DATA, not an ADR 0083 code module** — a subject-matter expert authors one, and requiring them to ship a package puts the mechanism out of reach of exactly the person it exists for. It layers over three surfaces that already exist (discipline-modes.json, the `behavior_prefs.interaction` contract path, the manifest contribution seam); only the knowledge bundle is new. The contract **rides the existing GET /me -> Conductor injection path rather than adding a second one**, and is CRAFT-SCOPED: the hook injects only the contract matching the claim in hand (which needed `t.discipline` on the active-claims read), and with no claim there is no craft and **nothing is injected** — silence beats guessing which expertise applies. Training is two-fold per the owner's 2026-09-17 ruling: documents they supplied, plus learnings captured from sessions worked in it (pointing at existing `learnings` rows, never a second corpus). The corpus is **inventoried, never inlined** — a document may run to 100k chars — so `speciality_documents` joins the recall ingester, because otherwise the contract's "search it with /recall" is a lie whose failure is silent. **`sellable` is recorded with no storefront behind it**: ADR 0107 defers the marketplace and explicitly rejected building one, so the flag captures the owner's decision when they make it and grants nothing — a deliberate partial implementation, recorded rather than silently made. Index scoping errs toward UNDER-sharing: only a public speciality's documents are corpus-wide, because `project` names a set the index cannot express.](0296-a-role-speciality-is-data-over-three-existing-surfaces.md) | roles / modules |
|
|
391
391
|
| 0297 | [**A task’s creator may retire it, and that is the ownership axis’s first route** ([task 1002443](https://cloudbongos.com/builders#/task/1002443), goal 1000095 — owner request 2026-07-25: *"the creator of that task should be able to abandon that task directly inside of the UI"*). Attribution itself shipped earlier and elsewhere (`core_227`, [task 1003278](https://cloudbongos.com/builders#/task/1003278)); what had not moved is that **retiring a task was a rank power and nothing else** — `task.abandon` floors at `metic` (ADR 0152), so a sub-Metic builder could file a task and then could not withdraw their own proposal. The model already had the vocabulary and had never used it: ADR 0151 §3 defines an **ownership axis** where a `scope:'own'` key authorizes nothing until a handler supplies the row's owner, R100 made `requirePermission` refuse such a key outright so `.own` can never degrade into `.any`, and it recorded that **zero call sites passed one**. This is that axis’s first real consumer. **Decision: two authorities, only one rank-shaped** — `task.abandon` (metic, any task) OR new `task.abandon.own` (xenos, a task you created, while it is still backlog/ready/blocked). Route becomes `requireBuilder` + an in-handler decision (the `POST /goals/:id/members` shape), pin `metic+archon`→`any-builder` so it now catches an accidental **tightening** as loudly as a gate removal. **The two facts resolve in two places on purpose:** the RANK fact is request-scoped and resolves before the transaction (uncached, ADR 0016); the OWNER fact is a column that can change under us, so `created_by` joins `abandonTask`’s existing `FOR UPDATE` SELECT and a new optional `authorize` callback decides under that lock. Reading `created_by` in the route would be a TOCTOU window; resolving permissions inside the transaction would hold a row lock across a second pool acquire. The decision is a PURE module (`abandon-authz.js`, the `goal-route-authz.js` precedent) so every branch is pinned DB-free and the hall hint and server verdict provably read one rule. **A creator’s window stops at the grader** — completed/confirmed stay cross-owner, because past the grader a retire is a ledger correction, not an author changing their mind; nothing is subtracted from `task.abandon`, pinned by a test. `counterpart: ['task.abandon']` is declared not derived, verb `act` not `manage` — `manage` would silently dominate every future narrower `task.*.own` key (the verb-blind escalation task 1003195 closed). **A null creator belongs to nobody and that is load-bearing:** ~1,357 pre-`core_227` tasks plus seed/restock/discord vectors are unattributed, so the owner comparison is the government resolver’s own — injected, never re-implemented, since a duplicated ownership comparison is how one quietly widens — and one slip would open every historical task to a xenos grant at once. Fail-closed throughout: a missing `government` port, a throwing resolver, and anything but an explicit `{ok:true}` all deny, and `authorize` runs BEFORE the idempotent already-abandoned return and the shipped/active-claim guards so an unauthorized caller cannot probe a row through a 200. No guard removed. Does NOT widen edit/promote/dependency (still Metic), does not touch `task.merge`, and does not backfill attribution — the control simply does not appear on tasks predating `core_227`.](0297-a-tasks-creator-may-retire-it.md) | authority / lifecycle / ownership |
|
|
392
|
+
| 0298 | [**The grader gets a reader lens: advisory, scoped to copy-bearing diffs, and it waits on a written voice** ([task 1003937](https://cloudbongos.com/builders#/task/1003937), goal 1000095 — Working area 6; owner decision 2026-09-17). Every artist review the cascade files opened with *“REVIEW THE GRADER … coach it”*, and it could not be followed: the v4 panel runs narc, quality, hacker and efficiency — completion, code quality, security, runtime cost — and not one of them reads a sentence for whether it is true, clear, in the project’s voice or worth a person’s attention. Four consecutive reviews hit the same wall and all four graded ships deservedly PASSED on the axes that were measured; the gate is not lenient, it is not pointed at this. `grader-prompt.js` already injects the craft’s written responsibility, but only when `discipline === ‘artist’`, so the unjudged case is copy shipped by someone whose craft is not the copy. **Decision: a fifth ADVISORY `reader` worker, on three settled terms.** It runs only where `modules/lifecycle/cascade.js`’s existing `hasCopyOrVisualWork` says the ship is copy-bearing — the same predicate the after-the-fact review uses, so the two can never disagree about coverage, and every other ship costs exactly what it costs today. It records `issues[]` and a `copy_score` and can never verdict `fail` or drag the panel to `concerns`, because [ADR 0241](0241-the-artist-gate-is-a-per-project-deploy-gate-that-reads-a-state.md) put the artist’s judgement on the DEPLOY and off the ship path; gating would need that ADR amended first. And it is NOT BUILT until the instance writes a voice guide — today the whole written standard is one dash rule in `DESIGN.md`, a tagline, a registry of which 1,860 strings exist, and one responsibility sentence, so a lens built now would record taste and call it a finding. Until the reader exists, STEP 1 asks the artist to WRITE DOWN what the grade could not see rather than to coach a lens that is not listening — followable today, and the corpus both the guide and the lens get written from. Nothing in the rubric, the active panel or any existing worker changes.](0298-the-reader-lens-is-advisory-and-waits-on-a-voice-guide.md) | grading / the artist’s loop / voice |
|