@bongos/core 1.19.962 → 1.19.964

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 (34) hide show
  1. package/.bongos-core.json +69 -34
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +2 -0
  4. package/clients/bongos-client/index.cjs +2 -0
  5. package/clients/bongos-client/index.d.ts +2 -0
  6. package/clients/bongos-client/index.mjs +2 -0
  7. package/docs/adr/0326-an-upgrade-may-add-a-deny-rule-to-a-file-the-instance-owns.md +51 -0
  8. package/docs/adr/README.md +1 -0
  9. package/docs/api/openapi.json +47 -2
  10. package/docs/api-reference.md +3 -2
  11. package/docs/copy-inventory.md +134 -128
  12. package/docs/copy-registry.json +212 -158
  13. package/docs/module-api-changelog.md +4 -0
  14. package/modules/hall-ui/public/goal-forest-lib.js +229 -0
  15. package/modules/hall-ui/public/goal-forest-render.js +151 -0
  16. package/modules/hall-ui/public/goals-page.js +6 -0
  17. package/modules/hall-ui/public/goals-render.js +9 -1
  18. package/modules/hall-ui/public/goals.css +26 -0
  19. package/modules/hall-ui/public/goals.html +19 -0
  20. package/modules/lifecycle/goal-forest.js +135 -0
  21. package/modules/lifecycle/routes/goals.js +8 -8
  22. package/package-lock.json +2 -2
  23. package/package.json +1 -1
  24. package/scripts/gds/claude-materialize.js +98 -8
  25. package/scripts/hall-preview/server.js +1 -0
  26. package/src/module-api.js +1 -1
  27. package/tests/claude_materialize.mjs +180 -4
  28. package/tests/goal_category_ui.mjs +2 -0
  29. package/tests/goal_criterion_confirm_ui.mjs +2 -0
  30. package/tests/goal_forest.mjs +160 -0
  31. package/tests/goal_forest_lib.mjs +153 -0
  32. package/tests/goal_forest_page.mjs +196 -0
  33. package/tests/goal_invite_consent.mjs +1 -1
  34. package/tests/helpers.mjs +7 -3
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.962",
6
- "core_contract": "1.19.962",
7
- "source_commit": "31bf829b41365d773f768e041a5593502bf02e0f",
5
+ "core_version": "1.19.964",
6
+ "core_contract": "1.19.964",
7
+ "source_commit": "3e8fc6d3d957def5dfc6804dc76ea914046c4934",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-22T17:31:08.462Z",
9
+ "built_at": "2026-09-22T21:39:06.402Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 514,
12
+ "docs_redacted": 515,
13
13
  "agent_docs_stubbed": 26,
14
- "functional_verbatim": 2358,
14
+ "functional_verbatim": 2364,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2898,
20
- "tree_sha256": "51d873c73f0ab88e3ec4e1baf9ec1d53a22994eeda22ed4dade6355993f5d527",
19
+ "file_count": 2905,
20
+ "tree_sha256": "a4efd0bd331bb162a3ae017d3443b3a124997f8b4030c0e34f37d3fe3cd10aeb",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -347,12 +347,12 @@
347
347
  {
348
348
  "path": "clients/bongos-client/README.md",
349
349
  "mode": "0000644",
350
- "sha256": "7d0b5d24baaf5f06e7fafe32a7c7cd1ea6c69746fb92c95a0a611ad776432cd8"
350
+ "sha256": "d1f7b1bdb4daf98ee7e0c11fd8bd51d202413fb8c1d2cf684d9389d58974b24f"
351
351
  },
352
352
  {
353
353
  "path": "clients/bongos-client/bongos-client.global.js",
354
354
  "mode": "0000644",
355
- "sha256": "71e5d4495bd293695bf42331bc20a6a3283fad8703663718209bd257953014f1"
355
+ "sha256": "c3e0241775c4cad76f8bc17edcc131bfdf649b6280b1ae9559bccf863a8b2658"
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": "525d496a716e92467593447bcbb71369d6bdb817605631023d9b081cd75ce4c1"
365
+ "sha256": "7a788085abb4096f48136d5908affd272da6c0b4129ed4de073b0934451e3028"
366
366
  },
367
367
  {
368
368
  "path": "clients/bongos-client/index.d.ts",
369
369
  "mode": "0000644",
370
- "sha256": "f134e3ba8380879dae51531cd0867bbda06c5229a5d0dd8b29fa2e0f026490e5"
370
+ "sha256": "692a295c1c9602f09da7f296b5e0550f7ae381a2f9fe34a060019cee6443287e"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/index.mjs",
374
374
  "mode": "0000644",
375
- "sha256": "2fe6fa6938205dce4bd1f48a3adc21b0898b78d3f125a9ee8c743497eaae6d22"
375
+ "sha256": "d420a781a25d4d4b8f038894b7829a1e024aafbd51a6d32266ed120cbb7a50c9"
376
376
  },
377
377
  {
378
378
  "path": "clients/bongos-client/package.json",
@@ -2119,20 +2119,25 @@
2119
2119
  "mode": "0000644",
2120
2120
  "sha256": "6ae902e7626feb915300f4b21b6d20ae3369116a86bf624bd614ac9616c3ac11"
2121
2121
  },
2122
+ {
2123
+ "path": "docs/adr/0326-an-upgrade-may-add-a-deny-rule-to-a-file-the-instance-owns.md",
2124
+ "mode": "0000644",
2125
+ "sha256": "7484e3b187c1aa84b23ef359baf8e86eabcf61164c9f75076af1e53ef04020f1"
2126
+ },
2122
2127
  {
2123
2128
  "path": "docs/adr/README.md",
2124
2129
  "mode": "0000644",
2125
- "sha256": "5db407e3565216666055365b11a5ff05b8901ff9c7fbaee011c93784c40762e6"
2130
+ "sha256": "d1c4f7bfd44a0bf74d545c813c603ba81283f67e9b767fcc1e6c704f03e8f441"
2126
2131
  },
2127
2132
  {
2128
2133
  "path": "docs/api-reference.md",
2129
2134
  "mode": "0000644",
2130
- "sha256": "9b60667dcf534053345a0de7ced96b840718de0ac89c7a4099a5a2c1ec24f17f"
2135
+ "sha256": "efc898a856bca98c7a182ef23d87bb0f5eb15da9574473bb9b23272ce71d506a"
2131
2136
  },
2132
2137
  {
2133
2138
  "path": "docs/api/openapi.json",
2134
2139
  "mode": "0000644",
2135
- "sha256": "dd53ef353bb82815a0d5de1959065ebcfd021584577257837990ec85ec8294b0"
2140
+ "sha256": "b64eee9aa839aa1b528436dfbaa8070f790f80f9d8d992bb6fd3cb06818a23d1"
2136
2141
  },
2137
2142
  {
2138
2143
  "path": "docs/architecture.md",
@@ -2157,12 +2162,12 @@
2157
2162
  {
2158
2163
  "path": "docs/copy-inventory.md",
2159
2164
  "mode": "0000644",
2160
- "sha256": "77cb83609d2a80e2c7520746181ef858839d37e8c0997b5dce42127d0c4c119c"
2165
+ "sha256": "a9b42bc18dbb2dddee7892c2e785011313eba87c8df0b86c3358b7af9050840b"
2161
2166
  },
2162
2167
  {
2163
2168
  "path": "docs/copy-registry.json",
2164
2169
  "mode": "0000644",
2165
- "sha256": "8d83ca0d16a1f9d0efc89f0331f6940592ce34e0dd6f92c448575497bce96548"
2170
+ "sha256": "bbd6bbd017e16f884388664bafcbe4bc6532e40968bc96546cced0b965c28f99"
2166
2171
  },
2167
2172
  {
2168
2173
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2692,7 +2697,7 @@
2692
2697
  {
2693
2698
  "path": "docs/module-api-changelog.md",
2694
2699
  "mode": "0000644",
2695
- "sha256": "fa3d4990413dcbd0bdf03dc4c6d3dbb4a8e966146fc594a914f4951468204668"
2700
+ "sha256": "4fc40bf68186c16de70b9d3406b67167c431d59bda15f996e759b79d97931b89"
2696
2701
  },
2697
2702
  {
2698
2703
  "path": "docs/modules-contract.md",
@@ -4894,6 +4899,16 @@
4894
4899
  "mode": "0000644",
4895
4900
  "sha256": "6cfd20a7dbf5fe4a20872d465eaeb401ead659523e4f2ae64565fd5ddf3aec7e"
4896
4901
  },
4902
+ {
4903
+ "path": "modules/hall-ui/public/goal-forest-lib.js",
4904
+ "mode": "0000644",
4905
+ "sha256": "ea6258a241922dbf8e3782e01c60a3b03a8c7d9213cdfeddb7bcb91be3227d14"
4906
+ },
4907
+ {
4908
+ "path": "modules/hall-ui/public/goal-forest-render.js",
4909
+ "mode": "0000644",
4910
+ "sha256": "b39c5544c30fedfc0a42b7cc6c59b6d630b03fd543d5c5bcc34172c494a0addc"
4911
+ },
4897
4912
  {
4898
4913
  "path": "modules/hall-ui/public/goal-inbox.js",
4899
4914
  "mode": "0000644",
@@ -4932,22 +4947,22 @@
4932
4947
  {
4933
4948
  "path": "modules/hall-ui/public/goals-page.js",
4934
4949
  "mode": "0000644",
4935
- "sha256": "a8eed7fe8913f7b03e0a213a706ff203f1e439539dd18258499042e84cb8fc1f"
4950
+ "sha256": "db143d107e2a58f7d3056556202a0864f6595f723ff302441c092e670f3c4ea3"
4936
4951
  },
4937
4952
  {
4938
4953
  "path": "modules/hall-ui/public/goals-render.js",
4939
4954
  "mode": "0000644",
4940
- "sha256": "5954a301097fefc7dc7d89d3ecbd6cc3fe9a70d1319c8a2ea648fab057ca923a"
4955
+ "sha256": "8d296e2ba0cafdcdf575d8bee24a0aeae3b03173480f2b7b5f5efd33f66e18b6"
4941
4956
  },
4942
4957
  {
4943
4958
  "path": "modules/hall-ui/public/goals.css",
4944
4959
  "mode": "0000644",
4945
- "sha256": "70e3506cdb11d7b108c9bae383169ae4319e5be7fcbb10a656da966db942b33a"
4960
+ "sha256": "b0421607c705c577e680f6f61d926189ef3ea367bef052ad1fab87f4e45937c5"
4946
4961
  },
4947
4962
  {
4948
4963
  "path": "modules/hall-ui/public/goals.html",
4949
4964
  "mode": "0000644",
4950
- "sha256": "8900bae7318f5e124c8cad0e679326426db29ba12ab9f96694a711590c93718f"
4965
+ "sha256": "c1236c20825ed1c767b29d5b3bdfca502e0a40439cfeb84b58d65923c267705a"
4951
4966
  },
4952
4967
  {
4953
4968
  "path": "modules/hall-ui/public/goals.js",
@@ -5824,6 +5839,11 @@
5824
5839
  "mode": "0000644",
5825
5840
  "sha256": "c22a0782ddf7a93deb40f700a2afab15a313925647bbdf424db777da5aa29aa1"
5826
5841
  },
5842
+ {
5843
+ "path": "modules/lifecycle/goal-forest.js",
5844
+ "mode": "0000644",
5845
+ "sha256": "3127ce171e80a40d87b6df030169e094a627ea0cb72d2d055f58d95419c77a07"
5846
+ },
5827
5847
  {
5828
5848
  "path": "modules/lifecycle/goal-from-idea.js",
5829
5849
  "mode": "0000644",
@@ -6017,7 +6037,7 @@
6017
6037
  {
6018
6038
  "path": "modules/lifecycle/routes/goals.js",
6019
6039
  "mode": "0000644",
6020
- "sha256": "1c97d9ba0c9f0ec0b6c1211e85e8f3c1bc3cc56719b5d86082715621af5c61a6"
6040
+ "sha256": "856f1ab40127186fa22c10fd37fbe57eb2d856cbdf75faee0e21209579ad887c"
6021
6041
  },
6022
6042
  {
6023
6043
  "path": "modules/lifecycle/routes/help-requests.js",
@@ -8082,12 +8102,12 @@
8082
8102
  {
8083
8103
  "path": "package-lock.json",
8084
8104
  "mode": "0000644",
8085
- "sha256": "de49dbe2000a605cf6e9d07c5c24aa63047624d3ab54c12802b877b5ed75c7b4"
8105
+ "sha256": "b4e4f2d52492eb82c66ee24349aa022cce2f178b293750ef6a585052eb76b100"
8086
8106
  },
8087
8107
  {
8088
8108
  "path": "package.json",
8089
8109
  "mode": "0000644",
8090
- "sha256": "0ceb618ebe37f5ce151ca6613d40ab19916b99395de3f0b6848b64d7ebf74057"
8110
+ "sha256": "4692c57d3dced8ca8e6b9894bd73c99b68cc8f002fa8d2cd63a7679ba5bef1b7"
8091
8111
  },
8092
8112
  {
8093
8113
  "path": "public-docs/index.html",
@@ -8432,7 +8452,7 @@
8432
8452
  {
8433
8453
  "path": "scripts/gds/claude-materialize.js",
8434
8454
  "mode": "0000644",
8435
- "sha256": "1bee053fafde559fad140069438ef41a3b5f8055cdc6330f159b7f9b4e9994c6"
8455
+ "sha256": "3baec8c96ee223786af2124265e45b43db92a5836349836107ffc71cd421c860"
8436
8456
  },
8437
8457
  {
8438
8458
  "path": "scripts/gds/claude-md-template.js",
@@ -9687,7 +9707,7 @@
9687
9707
  {
9688
9708
  "path": "scripts/hall-preview/server.js",
9689
9709
  "mode": "0000644",
9690
- "sha256": "f66f32220b4090f4dd29e0446ac4c2b68e8ac8dbf46a0f64487cadc68fc1a1b1"
9710
+ "sha256": "9c2fc2f33ddd4f51e715e89cc84d615c55aa070ee2173cdaa8fb7559f2f5a14a"
9691
9711
  },
9692
9712
  {
9693
9713
  "path": "scripts/hall-preview/task-visual.js",
@@ -10092,7 +10112,7 @@
10092
10112
  {
10093
10113
  "path": "src/module-api.js",
10094
10114
  "mode": "0000644",
10095
- "sha256": "4147e643fea1c191af854b7b08b98a6f6c8e49e384b10f7854b7213a0225f52a"
10115
+ "sha256": "8b2286bb26aa29c310fcfda30064d5a31f937b151912001dc4882f04d37dbe4e"
10096
10116
  },
10097
10117
  {
10098
10118
  "path": "src/module-loader/catalog.js",
@@ -10872,7 +10892,7 @@
10872
10892
  {
10873
10893
  "path": "tests/claude_materialize.mjs",
10874
10894
  "mode": "0000644",
10875
- "sha256": "256b4192e1ef8fb43539313c569b21435926ef9d149b04cd4903e342fcf14d45"
10895
+ "sha256": "23e00b61129b39e8b22696d22feba3810e276949e10ef81235468002a15ea855"
10876
10896
  },
10877
10897
  {
10878
10898
  "path": "tests/clawback_confirmed_backlog.mjs",
@@ -11512,7 +11532,7 @@
11512
11532
  {
11513
11533
  "path": "tests/goal_category_ui.mjs",
11514
11534
  "mode": "0000644",
11515
- "sha256": "9da4d0762b665e5e622a3a26d754e13206da52ef591b14bf35e73da5e8c39317"
11535
+ "sha256": "2993b7fdf8fc06682597ee3bc24888db18d163109b1476dbafff961edae9371e"
11516
11536
  },
11517
11537
  {
11518
11538
  "path": "tests/goal_cli.mjs",
@@ -11537,13 +11557,28 @@
11537
11557
  {
11538
11558
  "path": "tests/goal_criterion_confirm_ui.mjs",
11539
11559
  "mode": "0000644",
11540
- "sha256": "57397a645bbb488ab53bf380d9f75fc925039ced5e2740817e340e0fe25e4c34"
11560
+ "sha256": "431b3f3beea6d82d654f0c7ce3259975c47538456e17afa1428b39fa64037e9e"
11541
11561
  },
11542
11562
  {
11543
11563
  "path": "tests/goal_dependencies_read.mjs",
11544
11564
  "mode": "0000644",
11545
11565
  "sha256": "27e5e881185511e0562dcfe36b8d6926b3222a9443893456c5f3a04089e40db6"
11546
11566
  },
11567
+ {
11568
+ "path": "tests/goal_forest.mjs",
11569
+ "mode": "0000644",
11570
+ "sha256": "5aa1abc7faa95f51bc4b37f6b07ca033d503dfb4f589bd05b516d6578c55045b"
11571
+ },
11572
+ {
11573
+ "path": "tests/goal_forest_lib.mjs",
11574
+ "mode": "0000644",
11575
+ "sha256": "3b309358c195469bee0ab1ce95242914fbc0b1b3def0bb7de3d51dc09dd29c6a"
11576
+ },
11577
+ {
11578
+ "path": "tests/goal_forest_page.mjs",
11579
+ "mode": "0000644",
11580
+ "sha256": "5c173e79de212e014860f9e3e9b26099decbce4ab675c0f8614e6c1ebdf2a2da"
11581
+ },
11547
11582
  {
11548
11583
  "path": "tests/goal_graph.mjs",
11549
11584
  "mode": "0000644",
@@ -11552,7 +11587,7 @@
11552
11587
  {
11553
11588
  "path": "tests/goal_invite_consent.mjs",
11554
11589
  "mode": "0000644",
11555
- "sha256": "06795131276221ca2cc5792b1b6f2d102a3b16fbbd413ceb1a05600edf6ff68a"
11590
+ "sha256": "e46d8d02b4beb7d28b5da7fd360ff703b8b0a052231de8c0711bdf47558fa2df"
11556
11591
  },
11557
11592
  {
11558
11593
  "path": "tests/goal_map_lib.mjs",
@@ -12057,7 +12092,7 @@
12057
12092
  {
12058
12093
  "path": "tests/helpers.mjs",
12059
12094
  "mode": "0000644",
12060
- "sha256": "fe55acfa23dbc1fcd5e75893f88e4bcbff46d128aa99595511449be56299ddb3"
12095
+ "sha256": "e48846a413c484ad1eb2d3d1c110560d1b80572e25dfac2dcb56d6311acaa9d2"
12061
12096
  },
12062
12097
  {
12063
12098
  "path": "tests/hierarchy-config.mjs",
@@ -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
- - 409 operations across 61 resource groups
8
+ - 410 operations across 61 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -403,6 +403,8 @@ function createClient(opts = {}) {
403
403
  getGoalsIdConflicts: (args) => request("GET", "/goals/{id}/conflicts", { hasBody: false }, args),
404
404
  // POST /goals/{id}/conflicts/resolve — rank: any-builder — POST /goals/:id/conflicts/resolve
405
405
  postGoalsIdConflictsResolve: (args) => request("POST", "/goals/{id}/conflicts/resolve", { hasBody: true }, args),
406
+ // GET /goals/{id}/dependency-forest — rank: any-builder — GET /goals/:id/dependency-forest
407
+ getGoalsIdDependencyForest: (args) => request("GET", "/goals/{id}/dependency-forest", { hasBody: false }, args),
406
408
  // POST /goals/{id}/invitations — rank: any-builder — POST /goals/:id/invitations
407
409
  postGoalsIdInvitations: (args) => request("POST", "/goals/{id}/invitations", { hasBody: true }, args),
408
410
  // POST /goals/{id}/invitations/{reqId}/rescind — rank: any-builder — POST /goals/:id/invitations/:reqId/rescind
@@ -402,6 +402,8 @@ function createClient(opts = {}) {
402
402
  getGoalsIdConflicts: (args) => request("GET", "/goals/{id}/conflicts", { hasBody: false }, args),
403
403
  // POST /goals/{id}/conflicts/resolve — rank: any-builder — POST /goals/:id/conflicts/resolve
404
404
  postGoalsIdConflictsResolve: (args) => request("POST", "/goals/{id}/conflicts/resolve", { hasBody: true }, args),
405
+ // GET /goals/{id}/dependency-forest — rank: any-builder — GET /goals/:id/dependency-forest
406
+ getGoalsIdDependencyForest: (args) => request("GET", "/goals/{id}/dependency-forest", { hasBody: false }, args),
405
407
  // POST /goals/{id}/invitations — rank: any-builder — POST /goals/:id/invitations
406
408
  postGoalsIdInvitations: (args) => request("POST", "/goals/{id}/invitations", { hasBody: true }, args),
407
409
  // POST /goals/{id}/invitations/{reqId}/rescind — rank: any-builder — POST /goals/:id/invitations/:reqId/rescind
@@ -784,6 +784,8 @@ export interface BongosClient {
784
784
  getGoalsIdConflicts(args?: RequestArgs): Promise<GetGoalsIdConflictsResponse>;
785
785
  /** POST /goals/{id}/conflicts/resolve — rank: any-builder */
786
786
  postGoalsIdConflictsResolve(args: RequestArgs & { body: PostGoalsIdConflictsResolveRequest }): Promise<PostGoalsIdConflictsResolveResponse>;
787
+ /** GET /goals/{id}/dependency-forest — rank: any-builder */
788
+ getGoalsIdDependencyForest(args?: RequestArgs): Promise<ApiResponse>;
787
789
  /** POST /goals/{id}/invitations — rank: any-builder */
788
790
  postGoalsIdInvitations(args?: RequestArgs & { body?: PostGoalsIdInvitationsRequest }): Promise<PostGoalsIdInvitationsResponse>;
789
791
  /** POST /goals/{id}/invitations/{reqId}/rescind — rank: any-builder */
@@ -399,6 +399,8 @@ export function createClient(opts = {}) {
399
399
  getGoalsIdConflicts: (args) => request("GET", "/goals/{id}/conflicts", { hasBody: false }, args),
400
400
  // POST /goals/{id}/conflicts/resolve — rank: any-builder — POST /goals/:id/conflicts/resolve
401
401
  postGoalsIdConflictsResolve: (args) => request("POST", "/goals/{id}/conflicts/resolve", { hasBody: true }, args),
402
+ // GET /goals/{id}/dependency-forest — rank: any-builder — GET /goals/:id/dependency-forest
403
+ getGoalsIdDependencyForest: (args) => request("GET", "/goals/{id}/dependency-forest", { hasBody: false }, args),
402
404
  // POST /goals/{id}/invitations — rank: any-builder — POST /goals/:id/invitations
403
405
  postGoalsIdInvitations: (args) => request("POST", "/goals/{id}/invitations", { hasBody: true }, args),
404
406
  // POST /goals/{id}/invitations/{reqId}/rescind — rank: any-builder — POST /goals/:id/invitations/:reqId/rescind
@@ -0,0 +1,51 @@
1
+ # ADR 0326 — An upgrade may ADD a deny rule to a file the instance owns
2
+
3
+ - **Status:** accepted
4
+ - **Date:** 2026-09-22
5
+ - **Task:** [task 1004156](https://cloudbongos.com/builders#/task/1004156) (goal 1000090)
6
+ - **Deciders:** the owner, asked directly. The question is theirs because it narrows a rule the project drew on purpose; the implementation follows from the answer.
7
+ - **Amended:** 2026-09-22 by [task 1004158](https://cloudbongos.com/builders#/task/1004158) — the two shelf rules became starter-only; the top-up asks for the credential half alone. See the amendment note in *Decision* below.
8
+ - **Amends:** [ADR 0121](0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md) §2 — which already licensed "merge **or** leave-and-report" for a pre-existing file; this names the one merge that is provably safe, and extends it from `--adopt` to every materialize
9
+ - **Related:** task 1003962 (the allow-only starter) · task 1003966 (the deny half) · [task 1004155](https://cloudbongos.com/builders#/task/1004155) (the core's own list) · task 1004023 (an unparseable settings.json is copied through, not mangled)
10
+
11
+ ## Context
12
+
13
+ Task 1003966 gave the package-only instance starter its deny rules: no reading `.env` files, keys, or session tokens, and no `git stash`. It reached nobody who was already here.
14
+
15
+ The starter is written **only when `.claude/settings.json` is absent**. `bongos upgrade` materializes from the published package, which excludes `.claude/settings.json` on purpose (it is topology, not core), so an upgrade *always* takes the starter branch, *always* finds a settings.json already there, and left it alone. Every instance that took the allow-only starter from task 1003962 — the live one included — therefore kept it forever, and its local agent could still read keys and session tokens.
16
+
17
+ That was not an oversight. Task 1003962 drew the line deliberately: *"rewriting a file the instance owns is the line task 1003962 drew."* The prior session log recorded the remedy as manual — re-run `bongos init`, or delete the file so the next materialize writes a fresh starter.
18
+
19
+ The problem with a manual remedy for a security gap is that it protects the instances whose owners read release notes, which is not the set of instances that needs protecting.
20
+
21
+ ## Decision
22
+
23
+ **`bongos upgrade` adds a missing starter deny rule to an instance's own `settings.json`, and names each rule it added in the run output.**
24
+
25
+ The argument is that a deny rule is **monotonic in the safe direction**. An allow rule widens what the local agent may do, so writing one into a file the instance owns could hand an agent authority its owner never granted. A deny rule can only narrow. Appending one therefore cannot make any instance less safe than it was a moment earlier, whatever the file already said — which is what makes this the one merge worth doing without asking per-instance.
26
+
27
+ "Never clobber" survives in the sense that was always load-bearing: **nothing the instance wrote is removed, reordered, or rewritten.** Their allow rules, their own deny rules, their `ask` list, their hooks, their env, and every key outside `permissions` come back exactly as they were. New rules are appended after the ones already there.
28
+
29
+ ### The one rule the monotonicity argument does not fully cover
30
+
31
+ The credential rules are pure safety: nothing an instance legitimately does requires reading its own session token from inside an agent session. **The two shelf rules (`Bash(git stash:*)`, `PowerShell(git stash:*)`) are different in kind** — they guard a *workflow*, not a secret. They are in the top-up set anyway, because task 1004156's done-when says an old instance ends up with *the starter's* deny rules and because for an instance they are the only layer that exists (the `git-guard` hook is topology and does not ship).
32
+
33
+ The consequence is worth stating plainly rather than discovering: an instance whose builders used the repo-global shelf as a set-aside fallback will find it blocked after its next upgrade, and — no provenance, deny beating allow — cannot re-enable it from `settings.json`. Every added rule is named in the run output, so this is visible when it happens. If it ever bites, excluding the two shelf rules from the top-up set (keeping them starter-only) is a one-line change.
34
+
35
+ > **AMENDED 2026-09-22 — the exclusion above was taken** ([task 1004158](https://cloudbongos.com/builders#/task/1004158)). Not because it bit, but because the owner, shown the trade-off, judged the asymmetry the wrong way round: the core should not silently withdraw a workflow an instance cannot give itself back, when what it buys is a guard against a *shared-state* hazard the instance may not even have (the stack is repo-global across worktrees, so a single-worktree instance is not exposed the way this repo is). `starterDeny` is now `credentialDeny` plus the shelf rules; the top-up asks for `credentialDeny` alone.
36
+ >
37
+ > **Two things this does not change.** A *fresh* instance still gets both shelf rules — there they are a visible default, present from the first commit and editable before any workflow has grown around it, which is the difference in kind the section above is really about. And because the top-up only ever appends, **an instance that already took them keeps them**: live `cloudbongos.com` gained both in its 0→20 run and its builders stay blocked until someone hand-edits that file. This amendment is forward-looking only, and deliberately so — an upgrade that started *removing* rules would give up the directionality the whole decision rests on.
38
+
39
+ ### What is deliberately NOT done
40
+
41
+ - **No provenance, and so no memory of a deletion.** An owner who deliberately removes a rule we add will get it back on the next upgrade, and because deny beats allow in Claude Code's permission order they cannot override it with an allow rule either. We considered recording what we added so a later deletion could be read as intent. It was rejected as speculative machinery for a case nobody has hit: the rules in question are "do not read credentials" and "do not `git stash`", and an instance that genuinely needs one lifted is a conversation, not a config toggle. Revisit if it is ever a real complaint.
42
+ - **A file we cannot parse is left byte-for-byte alone** and reported, the same posture task 1004023 took when the core's own settings.json would not parse. So is one whose `permissions` or `permissions.deny` is not the shape we expect. A half-understood rewrite of a permissions file is worse than the gap it closes.
43
+ - **The allow half is never topped up.** Only deny. The whole safety argument is directionality, and it does not survive being applied to a rule that grants.
44
+
45
+ ## Consequences
46
+
47
+ - An instance materialized before task 1003966 is protected on its next upgrade, with no action from its owner and nothing of theirs lost.
48
+ - `materializeClaude` gains `summary.settingsDenyAdded` (the rules added) and `summary.settingsDenyUncheckable` (why a file was skipped). Both are also printed through `log()` — `upgrade.js` does not iterate `summary.notes`, so a note alone would never reach the operator's terminal.
49
+ - **The top-up is reported in `writtenPaths` on the real run only, never on the dry run.** That list doubles as the set `bongos upgrade`'s clean-tree pre-flight *ignores* (task 1004122), and the waiver is justified by "materialize overwrites these unconditionally, so whatever they hold now is discarded either way" — which is exactly not true of a top-up, the one path here that preserves existing content. Listing it in the preview would stop an owner's half-finished edit to `settings.json` from halting the bump, and `--commit-pin` would then commit and push it unreviewed. Omitting it from the preview keeps that safety property; reporting it on the real run still hands it to `persistPin`, so the pin commit carries the added rules and the next upgrade does not read them as a human's stray work.
50
+ - A read that throws (a directory at that path, a locked or root-owned file) is caught and reported as uncheckable. This step runs *after* the pin moved and the migrations ran, so an uncaught throw would leave a half-applied upgrade.
51
+ - The test that asserted an instance's settings.json comes back **byte-identical** is superseded by a strictly stronger one: every rule it had is still there, unmoved, and it gained only deny rules. The weaker spelling was what froze the gap in place.
@@ -417,3 +417,4 @@ This keeps the decision history honest and traceable.
417
417
  | 0323 | [**Hosting is three shapes, and we are not the landlord** ([task 1004140](https://cloudbongos.com/builders#/task/1004140), goal 1000106 — BONGOS-V2). Five projects ran as one Node process each on the control-plane droplet, about $0.80/month apiece — the cheapest arrangement available, bought with ~4,600 lines of `provision*.js` that write systemd units, create unix accounts, render Caddy snippets, `createdb`, install backup timers and count memory against a ceiling. That is the cost nobody priced: **we are a landlord.** The owner reframed the question — build on what others maintain, and let an owner keep the deployment platform they already use. **Seven decisions.** The shapes become `byo-host` (the owner runs it), `cloud-host` (we stand it up for them) and `dedicated-cloud-host` (the same path, larger plan); `co-tenant` is **retired, not renamed**, because it means *a process on our box from our checkout* — the opposite of bring-your-own-host, so reusing the name would make every existing comment lie. **DigitalOcean hosts hubs only**, which closes [ADR 0145](0145-free-hosted-project-tier-isolation-and-domain-separation.md) Finding 1 by removing its precondition rather than hardening the cookie: with no customer code on a `cloudbongos.com` subdomain there is no tenant to receive the hub session. **Render is the default** — its Postgres carries PITR and automated backups on every paid tier; Fly's managed Postgres starts ~$38/mo and Railway's is explicitly unmanaged, which is the exact responsibility being shed. **Cloudflare is the front door, not the compute**: Workers is a V8-isolate runtime that would require rewriting Express and `pg`, and Containers is built for bursty workloads that sleep, which a hall with background sweeps and a live event stream does not survive. **No deployment-platform adapter is built at all** — their application already deploys itself from the repository, so the platform we do not talk to is the platform we do not have to add. **Secrets: the platform is the system of record and Bongos stores names, never values** — a manifest of name, purpose and environment, no application secret, no platform API token, no "is it set?" probe, because each of those makes us custodian of other companies' credentials for convenience the manifest already delivers; `byo-host` marks the manifest unverifiable rather than opening an exception. **The free tier becomes a capped trial**, since ~$14/project cannot be subsidised indefinitely. Per-project cost rises ~17×, which is the price of not being a landlord and the reason metering stops being deferred work. Mostly a DELETION: [ADR 0306](0306-instance-supervision-is-a-seam-with-systemd-as-the-default.md)'s supervision seam is not extended (Render supervises its own processes), [ADR 0285](0285-a-shared-box-holds-about-twelve-projects-per-gb-and-memory-is-the-wall.md) stays true and stops being load-bearing with its queued resize held rather than spent, and the hub's offsite backup becomes the highest-consequence open item. Rejected: AWS/GCP (2–3× the cost for a bare instance, plus an IAM and billing surface to learn — maintenance added where the goal is to remove it); keeping the shared box and fixing only the cookie (cheaper, closes the finding, leaves the landlord runner and answers nothing else); a Vercel/Netlify/Render adapter layer (speculative pluggability); Bongos as the secrets vault pushing values through platform APIs.](0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md) | hosting / provisioning / cost |
418
418
  | 0324 | [**The public npm CLI channel is retired** ([task 1004144](https://cloudbongos.com/builders#/task/1004144), goal 1000091 — BONGOS-V2). The owner deleted `@cloudbongos/cli` from the registry on 2026-09-22 (`npm view` → E404; the `@cloudbongos` scope is empty). This supersedes [ADR 0258](0258-the-public-cli-is-a-generated-client-package-not-the-published-core.md) and [ADR 0292](0292-both-install-paths-stay-and-vendoring-is-the-production-one.md) §2 — the latter titled "`@cloudbongos/cli` STAYS, on a new justification" and written *because* task 1003872 proposed removing it once the public core flip dissolved its original reason. 0292's measured argument (~0.5 MB front door vs a 46 MB core pull to print a task list) is still true and is NOT what changed; the owner's decision about carrying a public channel at all is. `scripts/gds/build-cli-package.js` + `tests/cli_package.mjs` are deleted, no doc offers `npx @cloudbongos/cli`, and the way in is the hall at `<origin>/builders` or a checkout. The COMPILED binary channel (`build-bongos.js` → `/downloads/bongos/*` via `config/bongos-cli.json`) is a different artifact and is untouched — the same near-twin task 1003889 warned about. Three tests used the package's FILES manifest as a stand-in for "what a terminal user can run" and now read `bin/bongos.js`'s verb table, which is what that set always meant.](0324-the-public-npm-cli-channel-is-retired.md) | distribution / CLI |
419
419
  | 0325 | [**The managed fleet control plane is the hub we already run** ([task 1001948](https://cloudbongos.com/builders#/task/1001948), goal 1000106 — BONGOS-V2). The spike was written against [ADR 0111](0111-instance-hosting-provisioning-module.md) §5/§7, which deferred the managed offering as **"genuinely greenfield (no fleet registry exists)"** behind two gates — Mercury and a real `bongos upgrade`. Both gates are shipped and **the premise is not**: measuring the call sites first changed the answer, as it did for [task 1004141](https://cloudbongos.com/builders#/task/1004141). The registry is `provisioning_instances` (owner, shape, domain, database, port, lifecycle, cost estimate, module selection, the liveness overlay and the served/available core-version snapshot), with `provisioning_intents` as the queue and `provisioning_events` as the audit trail; the operator is `scripts/gds/provision.js`, the single token-holder draining that queue behind ADR 0111 §2's trust boundary; oversight is `GET /provisioning/fleet` and `/fleet/cost-ledger`; and the update channel is not one mechanism but two shipped ones — the owner's per-instance deploy door ([ADR 0293](0293-the-owners-deploy-door-is-an-intent-the-control-plane-drains.md), health-gated with auto-rollback) and the opt-in patch-only sweep ([ADR 0136](0136-update-channel-subscription-policy.md)). **Decision: there is no greenfield fleet control plane to design, and none will be built — the hub IS it.** It never needed to sit *above* the per-repo databases [ADR 0100](0100-two-repo-instance-model.md) §3 locks: the roster is a hub table and the operator has never read one. The genuinely missing leg is a **platform leg** — `grep -rl RENDER_API scripts modules src` returns nothing, and after [ADR 0323](0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md) a `cloud-host` is a Render service — and this ADR **deliberately specifies none of it**, because that is [task 1004142](https://cloudbongos.com/builders#/task/1004142)'s with those files open and a second spec for one implementation is how two drift. The fleet **driven** and the fleet **observed** are different populations: `byo-host` is in the registry and operated by nobody, its liveness the [ADR 0252](0252-the-self-hosted-visibility-report-is-a-pull-and-auto-appear-buys-a-retraction-lever.md) pull, so every operator surface must state which it counts — a roster that mixes them reports a fleet-wide upgrade as complete while an unknown number were never asked. The operator holds **exactly one** credential and it is **its own** (the platform account token, root-only on the control plane, never the web tier, never per-customer); ADR 0323 D6's "names, never values" rule is about the CUSTOMER's secrets and is unchanged. Two gaps are filed rather than fixed here: the subscription roster living in `config/update-subscriptions.json` is the one fleet fact the roster route cannot report and a restored backup can lose independently of the rows it describes ([task 1004150](https://cloudbongos.com/builders#/task/1004150), a recommendation and not a ruling), and **`costEstimateUsd` returns 0 for every shape but `dedicated`** — measured live, all 24 fleet rows report `$0`, confidently and with no error, for projects about to cost ~\$14/month each ([task 1004148](https://cloudbongos.com/builders#/task/1004148)). **No fleet-wide "upgrade everything" button**: both channels are per-instance by construction, and one action that moves the whole fleet is the shape most likely to take every customer down at once. AGPL posture unchanged — ADR 0111 §5's one-sentence rule survives its own table. Rejected: building the separate control plane §5 described (a second registry and a second operator holding the same rows with nothing keeping them equal); specifying Render here; reading per-instance databases for fleet reporting; and continuing to defer the whole layer, which is now the reason the ledger reads \$0 for a fleet about to cost real money.](0325-the-managed-fleet-control-plane-is-the-hub-we-already-run.md) | hosting / fleet / provisioning |
420
+ | 0326 | [**An upgrade may ADD a deny rule to a file the instance owns** ([task 1004156](https://cloudbongos.com/builders#/task/1004156), goal 1000090 — BONGOS-V2). Task 1003966 gave the instance starter its deny rules — no reading `.env` files, keys or session tokens, no shelving with the repo-global stash — and they reached **nobody who was already here**. The starter is written only when `.claude/settings.json` is ABSENT, and `bongos upgrade` materializes from the published package, which excludes that file on purpose; so an upgrade always takes the starter branch, always finds a settings.json already there, and left it alone. Every instance on the allow-only starter from task 1003962 — the live one included — kept it forever. That was deliberate ("rewriting a file the instance owns is the line task 1003962 drew"), and the recorded remedy was manual: re-run `bongos init`, or delete the file. **A manual remedy for a security gap protects the instances whose owners read release notes, which is not the set that needs protecting.** The owner's call: ADD the missing deny rules and NAME each one in the run output. The argument is that a deny rule is **monotonic in the safe direction** — an allow rule widens what the local agent may do, a deny rule can only narrow, so appending one cannot make any instance less safe than it was a moment earlier. That is what makes this the one merge worth doing without asking per-instance, and it extends [ADR 0121](0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md) §2's already-licensed "merge OR leave-and-report" from `--adopt` to every materialize. "Never clobber" survives in the sense that was load-bearing: **nothing the instance wrote is removed, reordered or rewritten** — their allow rules, own denies, `ask` list, hooks, env and every key outside `permissions` come back exactly as they were, with new rules appended after. Deliberately NOT done: **no provenance**, so an owner who deletes a rule we add gets it back next upgrade and (deny beating allow in Claude Code's order) cannot override it with an allow — rejected as speculative machinery for a case nobody has hit, revisit on a real complaint; a file that will not parse, or whose `permissions`/`permissions.deny` is not the expected shape, is left BYTE-FOR-BYTE alone and reported, the posture task 1004023 took for the core's own file, because a half-understood rewrite of a permissions file is worse than the gap; and **the allow half is never topped up** — the safety argument is directionality and does not survive being applied to a rule that grants. `materializeClaude` gains `summary.settingsDenyAdded` + `settingsDenyUncheckable`, both printed through `log()` since `upgrade.js` does not iterate `summary.notes`. The test asserting an instance's settings.json comes back byte-identical is superseded by a strictly stronger one — every rule still there, unmoved, deny-only growth — the weaker spelling being what froze the gap in place. **AMENDED 2026-09-22 by [task 1004158](https://cloudbongos.com/builders#/task/1004158): the two shelf rules are now starter-only and the top-up asks for the CREDENTIAL half alone.** 0326 itself named this exclusion as the remedy if the rule ever bit; the owner took it ahead of that, because the monotonicity argument licenses a rule about reading a secret and does not reach one that guards a workflow — with no provenance and deny beating allow, an instance that loses the shelf cannot give it back. A fresh instance still gets both. The top-up only ever appends, so this is **forward-looking only**: an instance that already took them keeps them, live included.](0326-an-upgrade-may-add-a-deny-rule-to-a-file-the-instance-owns.md) | security / instance onboarding |
@@ -6238,7 +6238,7 @@
6238
6238
  "goals"
6239
6239
  ],
6240
6240
  "summary": "GET /goals/:id/conflicts",
6241
- "description": "GET /goals/:id/conflicts — the server-side task-conflict view (task 1736). Replaces the hall Goals page's client-side exact-string approximation (the page feature-detects on 404): glob-aware touches[] intersection via the canonical path-match machinery, claim-aware severity, and cross-goal overlaps against other OPEN goals sharing scope_modules. Detection only — resolution is the POST below. rank: any-builder — a read; the same audience as GET /goals/:id.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
6241
+ "description": "GET /goals/:id/conflicts — the server-side task-conflict view (task 1736). Replaces the hall Goals page's client-side exact-string approximation (the page feature-detects on 404): glob-aware touches[] intersection via the canonical path-match machinery, claim-aware severity, and cross-goal overlaps against other OPEN goals sharing scope_modules. Detection only — resolution is the POST below. rank: any-builder — a read, GET /goals/:id's audience.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
6242
6242
  "x-rank": "any-builder",
6243
6243
  "x-source": "modules/lifecycle/routes/goals.js",
6244
6244
  "parameters": [
@@ -6346,6 +6346,51 @@
6346
6346
  ]
6347
6347
  }
6348
6348
  },
6349
+ "/goals/{id}/dependency-forest": {
6350
+ "get": {
6351
+ "operationId": "get_goals_id_dependency_forest",
6352
+ "tags": [
6353
+ "goals"
6354
+ ],
6355
+ "summary": "GET /goals/:id/dependency-forest",
6356
+ "description": "GET /goals/:id/dependency-forest, the per-goal task dependency drill-down (task 1003480, ADR 0227 §6.4).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
6357
+ "x-rank": "any-builder",
6358
+ "x-source": "modules/lifecycle/routes/goals.js",
6359
+ "parameters": [
6360
+ {
6361
+ "name": "id",
6362
+ "in": "path",
6363
+ "required": true,
6364
+ "schema": {
6365
+ "type": "string"
6366
+ },
6367
+ "description": "Path parameter `id`."
6368
+ }
6369
+ ],
6370
+ "responses": {
6371
+ "200": {
6372
+ "description": "Success."
6373
+ },
6374
+ "400": {
6375
+ "$ref": "#/components/responses/BadRequest"
6376
+ },
6377
+ "401": {
6378
+ "$ref": "#/components/responses/Unauthorized"
6379
+ },
6380
+ "403": {
6381
+ "$ref": "#/components/responses/Forbidden"
6382
+ },
6383
+ "404": {
6384
+ "$ref": "#/components/responses/NotFound"
6385
+ }
6386
+ },
6387
+ "security": [
6388
+ {
6389
+ "builderSession": []
6390
+ }
6391
+ ]
6392
+ }
6393
+ },
6349
6394
  "/goals/{id}/invitations": {
6350
6395
  "post": {
6351
6396
  "operationId": "post_goals_id_invitations",
@@ -26015,7 +26060,7 @@
26015
26060
  "description": "A required dependency/feature is not configured or is temporarily down."
26016
26061
  }
26017
26062
  },
26018
- "x-endpoint-count": 409,
26063
+ "x-endpoint-count": 410,
26019
26064
  "x-schema-count": 448,
26020
26065
  "x-undocumented-bodies": 9,
26021
26066
  "x-response-schemas": 304,
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Bongos API reference
4
4
 
5
- > **Generated from the live route files** — the route file is authoritative. 409 endpoints across 67 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 410 endpoints across 67 route files.
6
6
  > Machine-readable spec: [`docs/api/openapi.json`](api/openapi.json) (OpenAPI 3.1). Rendered docs site: **`/docs`** (e.g. `cloudbongos.com/docs`).
7
7
 
8
8
  Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust-boundary-server-enforced-permissions.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -261,7 +261,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
261
261
  | GET | `/api/bongos/github/repos` | `any-builder` | — | acts only on the caller's OWN GitHub identity (the token they granted). |
262
262
  | POST | `/api/bongos/github/repos` | `any-builder` | `name` | creates a repo in the caller's OWN account. |
263
263
 
264
- ## `goals` (32)
264
+ ## `goals` (33)
265
265
 
266
266
  | Method | Path | Rank | Body | Description |
267
267
  |---|---|---|---|---|
@@ -274,6 +274,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
274
274
  | PATCH | `/api/bongos/goals/:id/category` | `any-builder` | — | PATCH /goals/:id/category — body { category_id } (null clears it). |
275
275
  | GET | `/api/bongos/goals/:id/conflicts` | `any-builder` | — | GET /goals/:id/conflicts — the server-side task-conflict view (task 1736). |
276
276
  | POST | `/api/bongos/goals/:id/conflicts/resolve` | `any-builder` | `action`, `note`, `touches`, `first_task_id`, `then_task_id`, `task_id` | POST /goals/:id/conflicts/resolve — the owner/manager resolution actions for a detected conflict (task 1736; authority model ADR 0106): s… |
277
+ | GET | `/api/bongos/goals/:id/dependency-forest` | `any-builder` | — | GET /goals/:id/dependency-forest, the per-goal task dependency drill-down (task 1003480, ADR 0227 §6.4). |
277
278
  | POST | `/api/bongos/goals/:id/invitations` | `any-builder` | `note`, `builder_id` | POST /goals/:id/invitations { builder_id, note? } — an owner\|manager\|Archon invites a builder (task 1952). |
278
279
  | POST | `/api/bongos/goals/:id/invitations/:reqId/rescind` | `any-builder` | — | POST /goals/:id/invitations/:reqId/rescind — an owner\|manager\|Archon takes back a PENDING invitation the goal sent (task 1002971): the ma… |
279
280
  | POST | `/api/bongos/goals/:id/invitations/:reqId/respond` | `any-builder` | `action` | POST /goals/:id/invitations/:reqId/respond { action: accept\|decline } — ONLY the invited builder resolves their OWN pending invite (task … |