@bongos/core 1.19.813 → 1.19.814

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.
@@ -3,9 +3,9 @@
3
3
  "generator": "scripts/gds/copy-inventory.js",
4
4
  "goal": 1000074,
5
5
  "counts": {
6
- "strings": 1856,
7
- "unique_ids": 1610,
8
- "certain": 1856,
6
+ "strings": 1860,
7
+ "unique_ids": 1614,
8
+ "certain": 1860,
9
9
  "heuristic": 0,
10
10
  "duplicate_ids": 170
11
11
  },
@@ -13,7 +13,7 @@
13
13
  "builders-hall": {
14
14
  "at": "modules/hall-ui/public",
15
15
  "files": 86,
16
- "strings": 1366
16
+ "strings": 1370
17
17
  },
18
18
  "status-dashboard": {
19
19
  "at": "modules/status-ui/public",
@@ -270,9 +270,9 @@
270
270
  "occurrences": 4,
271
271
  "at": [
272
272
  "modules/hall-ui/public/task.js:494",
273
- "modules/hall-ui/public/task.js:518",
274
- "modules/hall-ui/public/task.js:910",
275
- "modules/hall-ui/public/task.js:922"
273
+ "modules/hall-ui/public/task.js:530",
274
+ "modules/hall-ui/public/task.js:959",
275
+ "modules/hall-ui/public/task.js:971"
276
276
  ]
277
277
  },
278
278
  {
@@ -348,8 +348,8 @@
348
348
  "text": "Copy prompt",
349
349
  "occurrences": 3,
350
350
  "at": [
351
- "modules/hall-ui/public/task.js:742",
352
- "modules/hall-ui/public/task.js:763",
351
+ "modules/hall-ui/public/task.js:791",
352
+ "modules/hall-ui/public/task.js:812",
353
353
  "modules/hall-ui/public/work.js:599"
354
354
  ]
355
355
  },
@@ -721,7 +721,7 @@
721
721
  "occurrences": 2,
722
722
  "at": [
723
723
  "modules/hall-ui/public/project-settings.js:242",
724
- "modules/hall-ui/public/task.js:929"
724
+ "modules/hall-ui/public/task.js:978"
725
725
  ]
726
726
  },
727
727
  {
@@ -2154,7 +2154,7 @@
2154
2154
  "surface": "builders-hall",
2155
2155
  "text": "A dependency keeps this task out of the claimable queue until that one ships. Remove one with the × beside it under “Blocked by”.",
2156
2156
  "file": "modules/hall-ui/public/task.js",
2157
- "line": 595,
2157
+ "line": 607,
2158
2158
  "origin": "js-markup",
2159
2159
  "confidence": "certain"
2160
2160
  },
@@ -2271,7 +2271,7 @@
2271
2271
  "surface": "builders-hall",
2272
2272
  "text": "A shipped task cannot be retired — it is immutable history now.",
2273
2273
  "file": "modules/hall-ui/public/task.js",
2274
- "line": 719,
2274
+ "line": 747,
2275
2275
  "origin": "js-markup",
2276
2276
  "confidence": "certain"
2277
2277
  },
@@ -2316,7 +2316,7 @@
2316
2316
  "surface": "builders-hall",
2317
2317
  "text": "A task cannot wait for itself.",
2318
2318
  "file": "modules/hall-ui/public/task.js",
2319
- "line": 837,
2319
+ "line": 886,
2320
2320
  "origin": "js-notice",
2321
2321
  "confidence": "certain"
2322
2322
  },
@@ -2415,7 +2415,7 @@
2415
2415
  "surface": "builders-hall",
2416
2416
  "text": "Add dependency",
2417
2417
  "file": "modules/hall-ui/public/task.js",
2418
- "line": 595,
2418
+ "line": 607,
2419
2419
  "origin": "js-markup",
2420
2420
  "confidence": "certain"
2421
2421
  },
@@ -2811,7 +2811,7 @@
2811
2811
  "surface": "builders-hall",
2812
2812
  "text": "Awaiting the grader, or a confirmation, before it can ship.",
2813
2813
  "file": "modules/hall-ui/public/task.js",
2814
- "line": 698,
2814
+ "line": 710,
2815
2815
  "origin": "js-markup",
2816
2816
  "confidence": "certain"
2817
2817
  },
@@ -3234,7 +3234,7 @@
3234
3234
  "surface": "builders-hall",
3235
3235
  "text": "Choose a goal first.",
3236
3236
  "file": "modules/hall-ui/public/task.js",
3237
- "line": 885,
3237
+ "line": 934,
3238
3238
  "origin": "js-notice",
3239
3239
  "confidence": "certain"
3240
3240
  },
@@ -3540,7 +3540,7 @@
3540
3540
  "surface": "builders-hall",
3541
3541
  "text": "Confirm that verification for #{…} actually passed?",
3542
3542
  "file": "modules/hall-ui/public/task.js",
3543
- "line": 778,
3543
+ "line": 827,
3544
3544
  "origin": "js-notice",
3545
3545
  "confidence": "certain"
3546
3546
  },
@@ -3675,7 +3675,7 @@
3675
3675
  "surface": "builders-hall",
3676
3676
  "text": "Copy prompt",
3677
3677
  "file": "modules/hall-ui/public/task.js",
3678
- "line": 742,
3678
+ "line": 791,
3679
3679
  "origin": "js-markup",
3680
3680
  "confidence": "certain"
3681
3681
  },
@@ -3684,7 +3684,7 @@
3684
3684
  "surface": "builders-hall",
3685
3685
  "text": "Copy prompt",
3686
3686
  "file": "modules/hall-ui/public/task.js",
3687
- "line": 763,
3687
+ "line": 812,
3688
3688
  "origin": "js-text-assign",
3689
3689
  "confidence": "certain"
3690
3690
  },
@@ -3918,7 +3918,7 @@
3918
3918
  "surface": "builders-hall",
3919
3919
  "text": "Could not load",
3920
3920
  "file": "modules/hall-ui/public/task.js",
3921
- "line": 929,
3921
+ "line": 978,
3922
3922
  "origin": "js-text-assign",
3923
3923
  "confidence": "certain"
3924
3924
  },
@@ -4062,7 +4062,7 @@
4062
4062
  "surface": "builders-hall",
4063
4063
  "text": "Could not load {…}",
4064
4064
  "file": "modules/hall-ui/public/task.js",
4065
- "line": 922,
4065
+ "line": 971,
4066
4066
  "origin": "js-markup",
4067
4067
  "confidence": "certain"
4068
4068
  },
@@ -4917,7 +4917,7 @@
4917
4917
  "surface": "builders-hall",
4918
4918
  "text": "Enter the id of the task this one should wait for.",
4919
4919
  "file": "modules/hall-ui/public/task.js",
4920
- "line": 834,
4920
+ "line": 883,
4921
4921
  "origin": "js-notice",
4922
4922
  "confidence": "certain"
4923
4923
  },
@@ -6231,7 +6231,7 @@
6231
6231
  "surface": "builders-hall",
6232
6232
  "text": "Last claimed by",
6233
6233
  "file": "modules/hall-ui/public/task.js",
6234
- "line": 640,
6234
+ "line": 652,
6235
6235
  "origin": "js-markup",
6236
6236
  "confidence": "certain"
6237
6237
  },
@@ -6753,7 +6753,7 @@
6753
6753
  "surface": "builders-hall",
6754
6754
  "text": "Move to goal",
6755
6755
  "file": "modules/hall-ui/public/task.js",
6756
- "line": 565,
6756
+ "line": 577,
6757
6757
  "origin": "js-markup",
6758
6758
  "confidence": "certain"
6759
6759
  },
@@ -7059,7 +7059,7 @@
7059
7059
  "surface": "builders-hall",
7060
7060
  "text": "No open goals in this version",
7061
7061
  "file": "modules/hall-ui/public/task.js",
7062
- "line": 564,
7062
+ "line": 576,
7063
7063
  "origin": "js-markup",
7064
7064
  "confidence": "certain"
7065
7065
  },
@@ -7212,7 +7212,7 @@
7212
7212
  "surface": "builders-hall",
7213
7213
  "text": "Not found",
7214
7214
  "file": "modules/hall-ui/public/task.js",
7215
- "line": 917,
7215
+ "line": 966,
7216
7216
  "origin": "js-text-assign",
7217
7217
  "confidence": "certain"
7218
7218
  },
@@ -7842,7 +7842,7 @@
7842
7842
  "surface": "builders-hall",
7843
7843
  "text": "Pick a priority first.",
7844
7844
  "file": "modules/hall-ui/public/task.js",
7845
- "line": 819,
7845
+ "line": 868,
7846
7846
  "origin": "js-notice",
7847
7847
  "confidence": "certain"
7848
7848
  },
@@ -7968,7 +7968,7 @@
7968
7968
  "surface": "builders-hall",
7969
7969
  "text": "Priority is already {…}.",
7970
7970
  "file": "modules/hall-ui/public/task.js",
7971
- "line": 822,
7971
+ "line": 871,
7972
7972
  "origin": "js-notice",
7973
7973
  "confidence": "certain"
7974
7974
  },
@@ -8715,7 +8715,7 @@
8715
8715
  "surface": "builders-hall",
8716
8716
  "text": "Retire task {…}? It leaves the claimable queue. Promote restores it to the backlog.",
8717
8717
  "file": "modules/hall-ui/public/task.js",
8718
- "line": 872,
8718
+ "line": 921,
8719
8719
  "origin": "js-notice",
8720
8720
  "confidence": "certain"
8721
8721
  },
@@ -8733,7 +8733,7 @@
8733
8733
  "surface": "builders-hall",
8734
8734
  "text": "Retire this task",
8735
8735
  "file": "modules/hall-ui/public/task.js",
8736
- "line": 726,
8736
+ "line": 775,
8737
8737
  "origin": "js-markup",
8738
8738
  "confidence": "certain"
8739
8739
  },
@@ -8742,7 +8742,7 @@
8742
8742
  "surface": "builders-hall",
8743
8743
  "text": "Retire this task…",
8744
8744
  "file": "modules/hall-ui/public/task.js",
8745
- "line": 737,
8745
+ "line": 786,
8746
8746
  "origin": "js-markup",
8747
8747
  "confidence": "certain"
8748
8748
  },
@@ -8850,7 +8850,7 @@
8850
8850
  "surface": "builders-hall",
8851
8851
  "text": "Say why it is being retired — the reason goes in the record.",
8852
8852
  "file": "modules/hall-ui/public/task.js",
8853
- "line": 871,
8853
+ "line": 920,
8854
8854
  "origin": "js-notice",
8855
8855
  "confidence": "certain"
8856
8856
  },
@@ -9093,7 +9093,7 @@
9093
9093
  "surface": "builders-hall",
9094
9094
  "text": "Set priority",
9095
9095
  "file": "modules/hall-ui/public/task.js",
9096
- "line": 595,
9096
+ "line": 607,
9097
9097
  "origin": "js-markup",
9098
9098
  "confidence": "certain"
9099
9099
  },
@@ -9174,7 +9174,7 @@
9174
9174
  "surface": "builders-hall",
9175
9175
  "text": "Ship it",
9176
9176
  "file": "modules/hall-ui/public/task.js",
9177
- "line": 694,
9177
+ "line": 706,
9178
9178
  "origin": "js-markup",
9179
9179
  "confidence": "certain"
9180
9180
  },
@@ -9192,7 +9192,7 @@
9192
9192
  "surface": "builders-hall",
9193
9193
  "text": "Shipped {…}{…}, {…}.",
9194
9194
  "file": "modules/hall-ui/public/task.js",
9195
- "line": 675,
9195
+ "line": 687,
9196
9196
  "origin": "js-markup",
9197
9197
  "confidence": "certain"
9198
9198
  },
@@ -9408,7 +9408,7 @@
9408
9408
  "surface": "builders-hall",
9409
9409
  "text": "Someone is holding a claim on this task. It has to be released before the task can be retired.",
9410
9410
  "file": "modules/hall-ui/public/task.js",
9411
- "line": 721,
9411
+ "line": 749,
9412
9412
  "origin": "js-markup",
9413
9413
  "confidence": "certain"
9414
9414
  },
@@ -9660,7 +9660,7 @@
9660
9660
  "surface": "builders-hall",
9661
9661
  "text": "Task {…}",
9662
9662
  "file": "modules/hall-ui/public/task.js",
9663
- "line": 518,
9663
+ "line": 530,
9664
9664
  "origin": "js-markup",
9665
9665
  "confidence": "certain"
9666
9666
  },
@@ -9669,7 +9669,7 @@
9669
9669
  "surface": "builders-hall",
9670
9670
  "text": "Task {…}",
9671
9671
  "file": "modules/hall-ui/public/task.js",
9672
- "line": 910,
9672
+ "line": 959,
9673
9673
  "origin": "js-markup",
9674
9674
  "confidence": "certain"
9675
9675
  },
@@ -9678,7 +9678,7 @@
9678
9678
  "surface": "builders-hall",
9679
9679
  "text": "Task {…}",
9680
9680
  "file": "modules/hall-ui/public/task.js",
9681
- "line": 922,
9681
+ "line": 971,
9682
9682
  "origin": "js-markup",
9683
9683
  "confidence": "certain"
9684
9684
  },
@@ -9714,7 +9714,7 @@
9714
9714
  "surface": "builders-hall",
9715
9715
  "text": "Tasks in the ledger are numbered separately from GitHub pull requests, so this may be a PR number rather than a task. The work board lists everything that does exist.",
9716
9716
  "file": "modules/hall-ui/public/task.js",
9717
- "line": 910,
9717
+ "line": 959,
9718
9718
  "origin": "js-markup",
9719
9719
  "confidence": "certain"
9720
9720
  },
@@ -10119,7 +10119,7 @@
10119
10119
  "surface": "builders-hall",
10120
10120
  "text": "The reason is recorded in the audit log. This is recoverable: a retired task can be restored to the backlog with Promote.",
10121
10121
  "file": "modules/hall-ui/public/task.js",
10122
- "line": 726,
10122
+ "line": 775,
10123
10123
  "origin": "js-markup",
10124
10124
  "confidence": "certain"
10125
10125
  },
@@ -10299,7 +10299,7 @@
10299
10299
  "surface": "builders-hall",
10300
10300
  "text": "The task feed did not answer. Nothing on the record has changed, only the read failed. Try again in a moment, or go back.",
10301
10301
  "file": "modules/hall-ui/public/task.js",
10302
- "line": 922,
10302
+ "line": 971,
10303
10303
  "origin": "js-markup",
10304
10304
  "confidence": "certain"
10305
10305
  },
@@ -10650,7 +10650,7 @@
10650
10650
  "surface": "builders-hall",
10651
10651
  "text": "This task has shipped and its credits have landed. Neither Ship it nor Confirm is available.",
10652
10652
  "file": "modules/hall-ui/public/task.js",
10653
- "line": 703,
10653
+ "line": 715,
10654
10654
  "origin": "js-markup",
10655
10655
  "confidence": "certain"
10656
10656
  },
@@ -10659,7 +10659,7 @@
10659
10659
  "surface": "builders-hall",
10660
10660
  "text": "This task is already retired. Promote restores it to the backlog.",
10661
10661
  "file": "modules/hall-ui/public/task.js",
10662
- "line": 723,
10662
+ "line": 751,
10663
10663
  "origin": "js-markup",
10664
10664
  "confidence": "certain"
10665
10665
  },
@@ -10884,7 +10884,7 @@
10884
10884
  "surface": "builders-hall",
10885
10885
  "text": "Wait for task",
10886
10886
  "file": "modules/hall-ui/public/task.js",
10887
- "line": 595,
10887
+ "line": 607,
10888
10888
  "origin": "js-markup",
10889
10889
  "confidence": "certain"
10890
10890
  },
@@ -11217,7 +11217,7 @@
11217
11217
  "surface": "builders-hall",
11218
11218
  "text": "Why retire this task?",
11219
11219
  "file": "modules/hall-ui/public/task.js",
11220
- "line": 726,
11220
+ "line": 775,
11221
11221
  "origin": "js-markup",
11222
11222
  "confidence": "certain"
11223
11223
  },
@@ -11392,6 +11392,42 @@
11392
11392
  "origin": "js-notice",
11393
11393
  "confidence": "certain"
11394
11394
  },
11395
+ {
11396
+ "id": "bcf33947aff6",
11397
+ "surface": "builders-hall",
11398
+ "text": "You created this task and it is already retired.",
11399
+ "file": "modules/hall-ui/public/task.js",
11400
+ "line": 767,
11401
+ "origin": "js-markup",
11402
+ "confidence": "certain"
11403
+ },
11404
+ {
11405
+ "id": "23c68db6db4e",
11406
+ "surface": "builders-hall",
11407
+ "text": "You created this task, but it has already moved past planning. Retiring it now is a change to the record, so it needs a Metic.",
11408
+ "file": "modules/hall-ui/public/task.js",
11409
+ "line": 772,
11410
+ "origin": "js-markup",
11411
+ "confidence": "certain"
11412
+ },
11413
+ {
11414
+ "id": "cf0c107a39fc",
11415
+ "surface": "builders-hall",
11416
+ "text": "You created this task, but it has shipped. Shipped work is immutable history — nobody can retire it, whatever their rank.",
11417
+ "file": "modules/hall-ui/public/task.js",
11418
+ "line": 765,
11419
+ "origin": "js-markup",
11420
+ "confidence": "certain"
11421
+ },
11422
+ {
11423
+ "id": "b91183c02c63",
11424
+ "surface": "builders-hall",
11425
+ "text": "You created this task, but someone is holding a claim on it. Once that is released you can retire it yourself.",
11426
+ "file": "modules/hall-ui/public/task.js",
11427
+ "line": 770,
11428
+ "origin": "js-markup",
11429
+ "confidence": "certain"
11430
+ },
11395
11431
  {
11396
11432
  "id": "da274462bb30",
11397
11433
  "surface": "builders-hall",
@@ -12126,7 +12162,7 @@
12126
12162
  "surface": "builders-hall",
12127
12163
  "text": "e.g. superseded by task 1002891",
12128
12164
  "file": "modules/hall-ui/public/task.js",
12129
- "line": 726,
12165
+ "line": 775,
12130
12166
  "origin": "js-markup",
12131
12167
  "confidence": "certain"
12132
12168
  },
@@ -12936,7 +12972,7 @@
12936
12972
  "surface": "builders-hall",
12937
12973
  "text": "task id",
12938
12974
  "file": "modules/hall-ui/public/task.js",
12939
- "line": 595,
12975
+ "line": 607,
12940
12976
  "origin": "js-markup",
12941
12977
  "confidence": "certain"
12942
12978
  },
@@ -13737,7 +13773,7 @@
13737
13773
  "surface": "builders-hall",
13738
13774
  "text": "{…}, no such task",
13739
13775
  "file": "modules/hall-ui/public/task.js",
13740
- "line": 910,
13776
+ "line": 959,
13741
13777
  "origin": "js-markup",
13742
13778
  "confidence": "certain"
13743
13779
  },
@@ -13782,7 +13818,7 @@
13782
13818
  "surface": "builders-hall",
13783
13819
  "text": "{…}{…} · {…}",
13784
13820
  "file": "modules/hall-ui/public/task.js",
13785
- "line": 637,
13821
+ "line": 649,
13786
13822
  "origin": "js-markup",
13787
13823
  "confidence": "certain"
13788
13824
  },
@@ -2100,5 +2100,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2100
2100
  landed since 1.19.811 with no explicit bump. run 35191850392. (task 1002620)
2101
2101
  1.19.813 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2102
2102
  landed since 1.19.812 with no explicit bump. run 35193306517. (task 1002620)
2103
+ 1.19.814 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2104
+ landed since 1.19.813 with no explicit bump. run 35194334679. (task 1002620)
2103
2105
  ---------------------------------------------------------------------------
2104
2106
  ```
@@ -898,7 +898,7 @@ function createClient(opts = {}) {
898
898
  getTasksId: (args) => request("GET", "/tasks/{id}", { hasBody: false }, args),
899
899
  // PATCH /tasks/{id} — rank: metic+archon — PATCH /tasks/:id
900
900
  patchTasksId: (args) => request("PATCH", "/tasks/{id}", { hasBody: true }, args),
901
- // POST /tasks/{id}/abandon — rank: metic+archon — POST /tasks/:id/abandon
901
+ // POST /tasks/{id}/abandon — rank: any-builder — POST /tasks/:id/abandon
902
902
  postTasksIdAbandon: (args) => request("POST", "/tasks/{id}/abandon", { hasBody: true }, args),
903
903
  // POST /tasks/{id}/attest-gate — rank: any-builder — POST /tasks/:id/attest-gate
904
904
  postTasksIdAttestGate: (args) => request("POST", "/tasks/{id}/attest-gate", { hasBody: true }, args),
@@ -164,7 +164,16 @@ const PERMISSIONS = [
164
164
  { key: 'task.edit', system: false, floor: 'metic', guards: 'PATCH /tasks/:id' },
165
165
  { key: 'task.promote', system: false, floor: 'metic', guards: 'POST /tasks/:id/promote' },
166
166
  { key: 'task.demote', system: false, floor: 'metic', guards: 'POST /tasks/:id/demote' },
167
- { key: 'task.abandon', system: false, floor: 'metic', guards: 'POST /tasks/:id/abandon — scope removal; undo = POST /tasks/:id/promote (ADR 0152, was archon)' },
167
+ // task 1002443: now the CROSS-OWNER half of a pair. Floor and guards are
168
+ // unchanged — what is new is that the key DECLARES its ownership axis, so
169
+ // `task.abandon.own` (in the ownership block below) can name it as the escalation
170
+ // path a creator's own-scoped grant is measured against.
171
+ //
172
+ // Verb `act`, not `manage`: retiring a task is ONE reach into the row, and
173
+ // `manage` is the full-control verb — declaring it here would silently dominate
174
+ // every future narrower `task.*.own` key, which is exactly the verb-blind
175
+ // escalation task 1003195 closed.
176
+ { key: 'task.abandon', system: false, floor: 'metic', scope: 'any', resource: 'task', verb: 'act', guards: 'POST /tasks/:id/abandon — scope removal on ANY task; undo = POST /tasks/:id/promote (ADR 0152, was archon). The cross-owner counterpart of task.abandon.own (task 1002443)' },
168
177
  { key: 'task.merge', system: false, floor: 'metic', guards: 'POST /tasks/:id/merge — mark a duplicate task merged into another (task 1001478, the idea.triage merge analogue)' },
169
178
  { key: 'task.vote', system: false, floor: 'metic', guards: 'POST /tasks/:id/vote' },
170
179
  { key: 'task.dependency.manage', system: false, floor: 'metic', guards: 'POST|PUT|DELETE /tasks/:id/dependencies (same-tier)' },
@@ -317,6 +326,24 @@ const PERMISSIONS = [
317
326
  // marker here. Exactly why scope is declared data: the suffix rule only runs the
318
327
  // safe direction ('.own' ⇒ scope 'own'), never the converse.
319
328
  { key: 'me.wandering.set', system: false, floor: 'xenos', scope: 'own', resource: 'builder_prefs', verb: 'set', counterpart: [], guards: 'PATCH /me/wandering (clamped by maxLevelForRank) — ownership-scoped' },
329
+ // task 1002443 — the owner's 2026-07-25 request: "the creator of that task should
330
+ // be able to abandon that task directly inside of the UI". Retiring work you
331
+ // filed yourself is not a triage authority, so it does not want the metic floor
332
+ // that `task.abandon` carries; it wants the OWNERSHIP axis, which is precisely the
333
+ // narrower rule a rank cannot express (`whose row is this`).
334
+ //
335
+ // counterpart is REAL here, unlike task.act.own/memory.manage.own: `task.abandon`
336
+ // is the same `act` verb over the same `task` resource across every creator, so it
337
+ // genuinely subsumes retiring your own — a Metic keeps the power they have today
338
+ // without needing to be the creator, and the route admits on either branch through
339
+ // resolver.authorizeOwnedOrAny.
340
+ //
341
+ // The floor is the LOOSER half of the gate, never the whole of it (the
342
+ // `goal.manage.own` posture): holding this key authorizes nothing on its own, and
343
+ // the STATUS envelope — creator-abandon only while the task is backlog/ready/
344
+ // blocked, never completed/confirmed/shipped — is enforced in abandonTask under
345
+ // the same FOR UPDATE lock that performs the write, not here.
346
+ { key: 'task.abandon.own', system: false, floor: 'xenos', scope: 'own', resource: 'task', verb: 'act', counterpart: ['task.abandon'], guards: 'POST /tasks/:id/abandon on a task you CREATED (tasks.created_by), while it is backlog/ready/blocked and unclaimed — requireBuilder + in-handler authorizeOwnedOrAny; ownership-scoped (task 1002443)' },
320
347
  { key: 'cost.log', system: false, floor: 'xenos', guards: 'POST /cost' },
321
348
  { key: 'learning.create', system: false, floor: 'xenos', guards: 'POST /learnings' },
322
349
  { key: 'blocker.file', system: false, floor: 'xenos', guards: 'POST /blockers' },
@@ -0,0 +1,64 @@
1
+ -- government_015_task_abandon_own.sql — grant the new `task.abandon.own` atom to
2
+ -- every rank (task 1002443, ADR 0297).
3
+ --
4
+ -- WHAT IT IS. The owner's 2026-07-25 request: "the creator of that task should be
5
+ -- able to abandon that task directly inside of the UI." Retiring a task was a rank
6
+ -- power only (`task.abandon`, floor metic, governance_003), so a sub-Metic builder
7
+ -- could file a task and then could not withdraw their own proposal. The new key is
8
+ -- the ADR 0151 §3 OWNERSHIP axis, not a rank widening.
9
+ --
10
+ -- A BRAND-NEW key: nobody holds it yet, so every rung the floor implies is granted
11
+ -- here. RANK_SEED is a cumulative superset and this key floors at `xenos`, the
12
+ -- bottom of the ladder — so ALL FOUR rank-roles get a block. The drift guard
13
+ -- (tests/government_seed.mjs) compares the union of the run-once seed plus every
14
+ -- later grant migration against the floor-derived seed, per rank; minting the
15
+ -- catalog row WITHOUT this migration is exactly what that guard catches, and it did.
16
+ --
17
+ -- GRANTING IT TO EVERY RANK GIVES NOBODY THE POWER TO RETIRE ANYTHING ON ITS OWN.
18
+ -- That is the whole point of an ownership-scoped key and the reason a floor this low
19
+ -- is safe: holding it authorizes nothing until a handler supplies the concrete row's
20
+ -- owner. `requirePermission` REFUSES an own-scoped key outright (auth.js, R100) so it
21
+ -- can never gate a route unconditionally, and `resolveBuilderPermissions` returning
22
+ -- it is only ever half a question. The other half — `tasks.created_by` equals the
23
+ -- caller, and the task is still backlog/ready/blocked — is answered inside
24
+ -- `abandonTask`'s FOR UPDATE transaction (modules/lifecycle/abandon-authz.js).
25
+ --
26
+ -- `task.abandon` (floor metic) is UNCHANGED and is not re-granted here: governance_003
27
+ -- already granted it and migrations are run-once. It becomes this key's declared
28
+ -- cross-owner counterpart — same `act` verb, same `task` resource — so a Metic keeps
29
+ -- retiring any task without being its creator.
30
+ --
31
+ -- Additive only: one new permission key granted to four ranks; nothing is revoked.
32
+ -- Idempotent (ON CONFLICT DO NOTHING); forward-safe (INSERT only).
33
+ --
34
+ -- One block PER RANK, in the government_004/009/010/011 shape: the drift guard scans
35
+ -- for `SELECT '<rank>', unnest(ARRAY[…])` literally, so a combined
36
+ -- `unnest(ARRAY['xenos','thetes']), 'key'` form parses as zero grants and reds it.
37
+
38
+ BEGIN;
39
+
40
+ INSERT INTO government_rank_permissions (rank_key, permission_key)
41
+ SELECT 'xenos', unnest(ARRAY[
42
+ 'task.abandon.own'
43
+ ])
44
+ ON CONFLICT (rank_key, permission_key) DO NOTHING;
45
+
46
+ INSERT INTO government_rank_permissions (rank_key, permission_key)
47
+ SELECT 'thetes', unnest(ARRAY[
48
+ 'task.abandon.own'
49
+ ])
50
+ ON CONFLICT (rank_key, permission_key) DO NOTHING;
51
+
52
+ INSERT INTO government_rank_permissions (rank_key, permission_key)
53
+ SELECT 'metic', unnest(ARRAY[
54
+ 'task.abandon.own'
55
+ ])
56
+ ON CONFLICT (rank_key, permission_key) DO NOTHING;
57
+
58
+ INSERT INTO government_rank_permissions (rank_key, permission_key)
59
+ SELECT 'archon', unnest(ARRAY[
60
+ 'task.abandon.own'
61
+ ])
62
+ ON CONFLICT (rank_key, permission_key) DO NOTHING;
63
+
64
+ COMMIT;
@@ -509,6 +509,18 @@
509
509
  // should carry these permissions is a governance change that needs its own
510
510
  // ADR, so this surfaces controls only for builders who already hold the atoms.
511
511
  const canShape = isSupervisor;
512
+ // task 1002443 — the CREATOR axis, which is not a rank and so cannot live in
513
+ // canShape. `task.abandon.own` (floor xenos, ADR 0297) lets a builder retire a
514
+ // task THEY filed while it is still backlog/ready/blocked. Same display-hint
515
+ // posture as canShape: the server re-decides this under a row lock, and this
516
+ // line only chooses whether to draw the control.
517
+ //
518
+ // created_by is null on every task filed before core_227 and on system vectors
519
+ // (seed, restock, the Discord bug path), so isCreator is false for them and the
520
+ // control simply does not appear — never a button that would 403.
521
+ const CREATOR_RETIRABLE = ['backlog', 'ready', 'blocked'];
522
+ const isCreator = !!(viewer && t.created_by != null
523
+ && String(t.created_by) === String(viewer.id));
512
524
  // render() rebuilds #task-body wholesale, so a disclosure cannot keep its
513
525
  // state in the DOM. This re-renders the SAME data without a refetch — the
514
526
  // toggle is a view change, not a reason to ask the server anything.
@@ -713,7 +725,23 @@
713
725
  // active claim must be released first — both are 409s the server will raise
714
726
  // anyway, and both are knowable from this record. Offering the control and
715
727
  // letting it fail would teach the reader that the page guesses.
728
+ //
729
+ // task 1002443 — the control now has TWO audiences, and they are offered
730
+ // different amounts of it. A Metic+ keeps every branch below, over any task. A
731
+ // CREATOR who is not Metic+ gets it only on their own task and only while it is
732
+ // backlog/ready/blocked, because that is exactly what the server will admit:
733
+ // past the grader a retire is a ledger correction, not an author changing their
734
+ // mind. Outside that window the creator is told so in words, for the same reason
735
+ // the two refusals below are pre-answered — a control that cannot work teaches
736
+ // the reader that the page guesses.
716
737
  const claimIsLive = !!(lastClaim && !lastClaim.released_at);
738
+ // The creator's narrower window. This is a DISPLAY MIRROR of the server's own
739
+ // CREATOR_ABANDONABLE (modules/lifecycle/abandon-authz.js) — a browser file
740
+ // cannot require it, so the list is restated here and the server re-decides
741
+ // every call under a row lock. If that list moves, this one moves with it.
742
+ const creatorMayRetire = isCreator && !claimIsLive
743
+ && CREATOR_RETIRABLE.indexOf(t.status) !== -1;
744
+ const mayRetire = canShape || creatorMayRetire;
717
745
  let retire = '';
718
746
  if (canShape && t.status === 'shipped') {
719
747
  retire = '<p class="rec-actnote">A shipped task cannot be retired — it is immutable history now.</p>';
@@ -721,7 +749,28 @@
721
749
  retire = '<p class="rec-actnote">Someone is holding a claim on this task. It has to be released before the task can be retired.</p>';
722
750
  } else if (canShape && t.status === 'abandoned') {
723
751
  retire = '<p class="rec-actnote">This task is already retired. Promote restores it to the backlog.</p>';
724
- } else if (canShape) {
752
+ // THE CREATOR'S REFUSALS ARE ORDERED BY WHAT WOULD ACTUALLY UNBLOCK THEM, which
753
+ // is not the same order as the supervisor's above. Each branch names the ONE
754
+ // thing standing in the way, and must not promise a remedy that would still be
755
+ // refused — the failure this file's own rule warns about, applied to the words
756
+ // rather than to a button.
757
+ //
758
+ // shipped → immutable for EVERYONE, so it must not read as 'ask a Metic'.
759
+ // abandoned → already done.
760
+ // a live claim, on a task that is otherwise retirable (or 'active', which
761
+ // releases back to 'ready') → releasing genuinely unblocks it.
762
+ // anything else outside the window (completed/confirmed) → authority is the
763
+ // blocker, and a Metic really can act there.
764
+ } else if (!canShape && isCreator && t.status === 'shipped') {
765
+ retire = '<p class="rec-actnote">You created this task, but it has shipped. Shipped work is immutable history — nobody can retire it, whatever their rank.</p>';
766
+ } else if (!canShape && isCreator && t.status === 'abandoned') {
767
+ retire = '<p class="rec-actnote">You created this task and it is already retired.</p>';
768
+ } else if (!canShape && isCreator && claimIsLive
769
+ && (t.status === 'active' || CREATOR_RETIRABLE.indexOf(t.status) !== -1)) {
770
+ retire = '<p class="rec-actnote">You created this task, but someone is holding a claim on it. Once that is released you can retire it yourself.</p>';
771
+ } else if (!canShape && isCreator && !creatorMayRetire) {
772
+ retire = '<p class="rec-actnote">You created this task, but it has already moved past planning. Retiring it now is a change to the record, so it needs a Metic.</p>';
773
+ } else if (mayRetire) {
725
774
  retire = abandonOpen
726
775
  ? `
727
776
  <div class="td-form" id="abandon-form">