@bongos/core 1.24.1 → 1.24.3
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 +68 -43
- 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 +6 -0
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/adr/0385-money-lives-with-a-processor-credits-stay-a-project-meter.md +12 -1
- package/docs/adr/README.md +1 -1
- package/docs/api/openapi.json +140 -1
- package/docs/api-reference.md +5 -2
- package/docs/copy-inventory.md +11 -6
- package/docs/copy-registry.json +63 -8
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +2 -1
- package/docs/page-readings.json +35 -26
- package/modules/economy/governor-docket.js +12 -6
- package/modules/government/access-routes.js +70 -0
- package/modules/government/access.js +88 -0
- package/modules/government/asks.js +5 -2
- package/modules/government/db.js +38 -0
- package/modules/government/docket.js +12 -2
- package/modules/government/migrations/government_036_access_holders.sql +33 -0
- package/modules/government/routes/government.js +9 -0
- package/modules/government/routing.js +11 -3
- package/modules/government/waiting.js +4 -0
- package/modules/hall-ui/public/blockers-by-person.js +2 -0
- package/modules/hall-ui/public/government-access.js +108 -0
- package/modules/hall-ui/public/government.html +21 -0
- package/modules/hall-ui/public/street-inside.js +1 -1
- package/modules/hall-ui/records/blockers-people.md +14 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -0
- package/scripts/bongos/government-walk.js +3 -0
- package/src/bongos/route-rank-check.js +4 -0
- package/src/module-api.js +1 -1
- package/tests/access_holders.mjs +214 -0
- package/tests/government_board_membership.mjs +4 -1
- package/tests/government_routes.mjs +1 -1
- package/tests/government_seed.mjs +1 -0
- package/tests/governor_docket.mjs +7 -3
- package/tests/hall_street_inside.mjs +2 -2
package/docs/api-reference.md
CHANGED
|
@@ -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.
|
|
5
|
+
> **Generated from the live route files** — the route file is authoritative. 634 endpoints across 104 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`.
|
|
@@ -363,10 +363,13 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
|
|
|
363
363
|
| GET | `/api/bongos/goals/rollups` | `any-builder` | — | GET /goals/rollups?version= — one small row per goal: readiness counters, the last-activity timestamp, the craft set, and the next claima… |
|
|
364
364
|
| GET | `/api/bongos/goals/suggestions` | `any-builder` | — | GET /goals/suggestions — "which goal should this draft live in?", answered before anything is created (task 1003062 / R07). |
|
|
365
365
|
|
|
366
|
-
## `government` (
|
|
366
|
+
## `government` (41)
|
|
367
367
|
|
|
368
368
|
| Method | Path | Rank | Body | Description |
|
|
369
369
|
|---|---|---|---|---|
|
|
370
|
+
| GET | `/api/bongos/government/access` | `any-builder` | — | |
|
|
371
|
+
| POST | `/api/bongos/government/access/:accessKey/holders` | `archon` | — | |
|
|
372
|
+
| DELETE | `/api/bongos/government/access/:accessKey/holders/:builderId` | `archon` | — | |
|
|
370
373
|
| PUT | `/api/bongos/government/asks/:matterId` | `any-builder` | — | board.vote.cast — put an ASK on a docket matter (task 1004703): the one shape every request from an agent to a person takes. |
|
|
371
374
|
| POST | `/api/bongos/government/asks/:matterId/pass` | `any-builder` | `seat` | board.vote.cast — PASS AN ASK ON to another seat (task 1004705, the direction desk). |
|
|
372
375
|
| POST | `/api/bongos/government/asks/:matterId/unclear` | `any-builder` | `note` | board.vote.cast — "I DON'T UNDERSTAND THIS" (the "?" on a city card, owner 2026-10-23): puts a matter the flagger can see on the reword l… |
|
package/docs/copy-inventory.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
> Deterministic on a given tree — regenerate and commit rather than hand-editing.
|
|
5
5
|
> Machine-readable twin: [`copy-registry.json`](copy-registry.json).
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**3111 strings** across 3 surfaces · 2450 distinct pieces of copy · 3111 certain, 0 heuristic · 261 shown in more than one place.
|
|
8
8
|
|
|
9
9
|
## Surfaces
|
|
10
10
|
|
|
11
11
|
| surface | lives at | files | strings |
|
|
12
12
|
|---|---|---|---|
|
|
13
|
-
| `builders-hall` | `modules/hall-ui/public` |
|
|
13
|
+
| `builders-hall` | `modules/hall-ui/public` | 160 | 2013 |
|
|
14
14
|
| `status-dashboard` | `modules/status-ui/public` | 4 | 91 |
|
|
15
15
|
| `landing` | `modules/public-landing/public` | 10 | 1007 |
|
|
16
16
|
|
|
@@ -76,9 +76,9 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
76
76
|
| `eff70e59d12e` | 4x | Task {…} | modules/hall-ui/public/task.js:491, modules/hall-ui/public/task.js:527, modules/hall-ui/public/task.js:1022 |
|
|
77
77
|
| `72a29648399b` | 4x | Tweak a page | modules/hall-ui/public/tweak-editor.html:32, modules/hall-ui/public/tweak-editor.html:32, modules/hall-ui/public/tweak-editor.html:55 |
|
|
78
78
|
| `ed394c66d49c` | 4x | What the choice changes | modules/public-landing/public/projects.html:1342, modules/public-landing/public/projects.html:1430, modules/public-landing/public/projects.html:1442 |
|
|
79
|
-
| … | |
|
|
79
|
+
| … | | _221 more in the JSON registry_ | |
|
|
80
80
|
|
|
81
|
-
## `builders-hall` —
|
|
81
|
+
## `builders-hall` — 2013 strings
|
|
82
82
|
|
|
83
83
|
| id | conf | text | where |
|
|
84
84
|
|---|---|---|---|
|
|
@@ -251,6 +251,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
251
251
|
| `da910fee01d7` | certain | Browse goals → | `modules/hall-ui/public/goals.js:105` |
|
|
252
252
|
| `25b4ab94728a` | certain | Build from your own machine — get a copy of the project, sign in once, then work in Claude. | `modules/hall-ui/public/hall-render.js:817` |
|
|
253
253
|
| `08bfcc9198ba` | certain | Builder id | `modules/hall-ui/public/government.html:107` |
|
|
254
|
+
| `08bfcc9198ba` | certain | Builder id | `modules/hall-ui/public/government.html:127` |
|
|
254
255
|
| `fd1903586e8e` | certain | Builders hall · this session | `modules/hall-ui/public/craft-mode.js:670` |
|
|
255
256
|
| `306bc316184d` | certain | Builders you may know | `modules/hall-ui/public/profile-connections.js:158` |
|
|
256
257
|
| `60b248791dc3` | certain | Builders — {{worldName}} | `modules/hall-ui/public/roster.html:6` |
|
|
@@ -270,7 +271,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
270
271
|
| `181cfa50b127` | certain | By the numbers | `modules/hall-ui/public/profile.html:64` |
|
|
271
272
|
| `a015a43bfc7f` | certain | CLI access | `modules/hall-ui/public/settings.html:141` |
|
|
272
273
|
| `09e863eb90af` | certain | Can: {…} | `modules/hall-ui/public/government.js:911` |
|
|
273
|
-
| `084eb64bce72` | certain | Capabilities held by a machine identity, never by a person or a rank. Shown for completeness; nothing here can | `modules/hall-ui/public/government.html:
|
|
274
|
+
| `084eb64bce72` | certain | Capabilities held by a machine identity, never by a person or a rank. Shown for completeness; nothing here can | `modules/hall-ui/public/government.html:141` |
|
|
274
275
|
| `c31f00bce184` | certain | Card added. | `modules/hall-ui/public/settings-passkeys.js:92` |
|
|
275
276
|
| `3cd965c9e3b1` | certain | Card name | `modules/hall-ui/public/settings.html:186` |
|
|
276
277
|
| `6fad39976eaf` | certain | Card removed. | `modules/hall-ui/public/settings-passkeys.js:59` |
|
|
@@ -757,7 +758,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
757
758
|
| `9da6a9b67eea` | certain | Look around first | `modules/hall-ui/public/welcome-boot.js:197` |
|
|
758
759
|
| `4017ee030bc2` | certain | Lookback window | `modules/hall-ui/public/profile-charts.js:540` |
|
|
759
760
|
| `73677b6839d7` | certain | Looks good | `modules/hall-ui/public/studio.js:196` |
|
|
760
|
-
| `06b4ede3fb58` | certain | Machine principals | `modules/hall-ui/public/government.html:
|
|
761
|
+
| `06b4ede3fb58` | certain | Machine principals | `modules/hall-ui/public/government.html:140` |
|
|
761
762
|
| `b8a2b32fdbb1` | certain | Main role | `modules/hall-ui/public/settings.html:125` |
|
|
762
763
|
| `4088dac7b364` | certain | Make it a law | `modules/hall-ui/public/my-agents.js:418` |
|
|
763
764
|
| `d535454fac6d` | certain | Make it again | `modules/hall-ui/public/ai-studio.js:416` |
|
|
@@ -874,6 +875,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
874
875
|
| `1967d2176f2e` | certain | Nobody has an open ask right now. | `modules/hall-ui/public/collab.html:95` |
|
|
875
876
|
| `c65c9f5c02e3` | certain | Nobody is waiting on you. Requests reach you by role — | `modules/hall-ui/public/collab.html:54` |
|
|
876
877
|
| `d5cf262e671d` | certain | Nobody is writing this page. Take it, and every line here is yours to type over. | `modules/hall-ui/public/tweak-editor.js:323` |
|
|
878
|
+
| `380b924cd4a0` | certain | Nobody recorded — it falls to the owner | `modules/hall-ui/public/government-access.js:35` |
|
|
877
879
|
| `91c409a4aea5` | certain | Nobody vouched for this name — anyone can file a request naming anyone. Confirm who is asking before you admit | `modules/hall-ui/public/watch.js:397` |
|
|
878
880
|
| `4016b9cf8d57` | certain | None of your asks have been settled yet. | `modules/hall-ui/public/collab.html:145` |
|
|
879
881
|
| `36c97d6094bf` | certain | None yet. Yours will be the first. | `modules/hall-ui/public/lightbulb.js:90` |
|
|
@@ -983,6 +985,8 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
983
985
|
| `a2bd76ae030d` | certain | Opens this project's upgrade{…}: you see what would move, confirm it, and it installs, checks itself, and roll | `modules/hall-ui/public/settings-software-update.js:130` |
|
|
984
986
|
| `569980a263ae` | certain | Optional. This is the ledger link — a copy change ships as a task like every other change. | `modules/hall-ui/public/copy-desk.html:130` |
|
|
985
987
|
| `f2e9e8f21e8e` | certain | Or add someone without asking… | `modules/hall-ui/public/goals-render.js:1258` |
|
|
988
|
+
| `8b1e7aae1e5f` | certain | Outside access | `modules/hall-ui/public/government.html:123` |
|
|
989
|
+
| `20cf1adf4154` | certain | Outside access could not be read just now. | `modules/hall-ui/public/government-access.js:72` |
|
|
986
990
|
| `d89d1923ecf9` | certain | Over the last {…} days | `modules/hall-ui/public/watch.js:1287` |
|
|
987
991
|
| `695ffff13730` | certain | Over time | `modules/hall-ui/public/profile.html:76` |
|
|
988
992
|
| `5ded44da0cc5` | certain | Override requests | `modules/hall-ui/public/watch.html:137` |
|
|
@@ -1592,6 +1596,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1592
1596
|
| `f9ab9eb870a6` | certain | While you wait: install the Claude desktop app at | `modules/hall-ui/public/hall-render.js:471` |
|
|
1593
1597
|
| `74d8c58ef235` | certain | Who builds on this project, ranked by work shipped. This project's own ledger — everyone who builds here is li | `modules/hall-ui/public/roster.html:28` |
|
|
1594
1598
|
| `b79ea4077bc5` | certain | Who can use it | `modules/hall-ui/public/settings.html:306` |
|
|
1599
|
+
| `c6d830ca9e08` | certain | Who holds the keys outside the project, so a blocker that needs one reaches them. This is a record of who to a | `modules/hall-ui/public/government.html:124` |
|
|
1595
1600
|
| `045c629729b7` | certain | Who’s on this goal, and what they’ve contributed to it. | `modules/hall-ui/public/goals.html:219` |
|
|
1596
1601
|
| `5cc53380b1e8` | certain | Why (optional) | `modules/hall-ui/public/goals-render.js:1029` |
|
|
1597
1602
|
| `62ab2e60f629` | certain | Why is this better? | `modules/hall-ui/public/copy-desk.html:164` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
"generator": "scripts/bongos/copy-inventory.js",
|
|
4
4
|
"goal": 1000074,
|
|
5
5
|
"counts": {
|
|
6
|
-
"strings":
|
|
7
|
-
"unique_ids":
|
|
8
|
-
"certain":
|
|
6
|
+
"strings": 3111,
|
|
7
|
+
"unique_ids": 2450,
|
|
8
|
+
"certain": 3111,
|
|
9
9
|
"heuristic": 0,
|
|
10
|
-
"duplicate_ids":
|
|
10
|
+
"duplicate_ids": 261
|
|
11
11
|
},
|
|
12
12
|
"surfaces": {
|
|
13
13
|
"builders-hall": {
|
|
14
14
|
"at": "modules/hall-ui/public",
|
|
15
|
-
"files":
|
|
16
|
-
"strings":
|
|
15
|
+
"files": 160,
|
|
16
|
+
"strings": 2013
|
|
17
17
|
},
|
|
18
18
|
"status-dashboard": {
|
|
19
19
|
"at": "modules/status-ui/public",
|
|
@@ -1258,6 +1258,16 @@
|
|
|
1258
1258
|
"modules/hall-ui/public/goals.js:105"
|
|
1259
1259
|
]
|
|
1260
1260
|
},
|
|
1261
|
+
{
|
|
1262
|
+
"id": "08bfcc9198ba",
|
|
1263
|
+
"surface": "builders-hall",
|
|
1264
|
+
"text": "Builder id",
|
|
1265
|
+
"occurrences": 2,
|
|
1266
|
+
"at": [
|
|
1267
|
+
"modules/hall-ui/public/government.html:107",
|
|
1268
|
+
"modules/hall-ui/public/government.html:127"
|
|
1269
|
+
]
|
|
1270
|
+
},
|
|
1261
1271
|
{
|
|
1262
1272
|
"id": "60b248791dc3",
|
|
1263
1273
|
"surface": "builders-hall",
|
|
@@ -4561,6 +4571,15 @@
|
|
|
4561
4571
|
"origin": "html-text",
|
|
4562
4572
|
"confidence": "certain"
|
|
4563
4573
|
},
|
|
4574
|
+
{
|
|
4575
|
+
"id": "08bfcc9198ba",
|
|
4576
|
+
"surface": "builders-hall",
|
|
4577
|
+
"text": "Builder id",
|
|
4578
|
+
"file": "modules/hall-ui/public/government.html",
|
|
4579
|
+
"line": 127,
|
|
4580
|
+
"origin": "html-text",
|
|
4581
|
+
"confidence": "certain"
|
|
4582
|
+
},
|
|
4564
4583
|
{
|
|
4565
4584
|
"id": "fd1903586e8e",
|
|
4566
4585
|
"surface": "builders-hall",
|
|
@@ -4737,7 +4756,7 @@
|
|
|
4737
4756
|
"surface": "builders-hall",
|
|
4738
4757
|
"text": "Capabilities held by a machine identity, never by a person or a rank. Shown for completeness; nothing here can be granted.",
|
|
4739
4758
|
"file": "modules/hall-ui/public/government.html",
|
|
4740
|
-
"line":
|
|
4759
|
+
"line": 141,
|
|
4741
4760
|
"origin": "html-text",
|
|
4742
4761
|
"confidence": "certain"
|
|
4743
4762
|
},
|
|
@@ -9120,7 +9139,7 @@
|
|
|
9120
9139
|
"surface": "builders-hall",
|
|
9121
9140
|
"text": "Machine principals",
|
|
9122
9141
|
"file": "modules/hall-ui/public/government.html",
|
|
9123
|
-
"line":
|
|
9142
|
+
"line": 140,
|
|
9124
9143
|
"origin": "html-text",
|
|
9125
9144
|
"confidence": "certain"
|
|
9126
9145
|
},
|
|
@@ -10168,6 +10187,15 @@
|
|
|
10168
10187
|
"origin": "js-markup",
|
|
10169
10188
|
"confidence": "certain"
|
|
10170
10189
|
},
|
|
10190
|
+
{
|
|
10191
|
+
"id": "380b924cd4a0",
|
|
10192
|
+
"surface": "builders-hall",
|
|
10193
|
+
"text": "Nobody recorded — it falls to the owner",
|
|
10194
|
+
"file": "modules/hall-ui/public/government-access.js",
|
|
10195
|
+
"line": 35,
|
|
10196
|
+
"origin": "js-markup",
|
|
10197
|
+
"confidence": "certain"
|
|
10198
|
+
},
|
|
10171
10199
|
{
|
|
10172
10200
|
"id": "91c409a4aea5",
|
|
10173
10201
|
"surface": "builders-hall",
|
|
@@ -11149,6 +11177,24 @@
|
|
|
11149
11177
|
"origin": "js-markup",
|
|
11150
11178
|
"confidence": "certain"
|
|
11151
11179
|
},
|
|
11180
|
+
{
|
|
11181
|
+
"id": "8b1e7aae1e5f",
|
|
11182
|
+
"surface": "builders-hall",
|
|
11183
|
+
"text": "Outside access",
|
|
11184
|
+
"file": "modules/hall-ui/public/government.html",
|
|
11185
|
+
"line": 123,
|
|
11186
|
+
"origin": "html-text",
|
|
11187
|
+
"confidence": "certain"
|
|
11188
|
+
},
|
|
11189
|
+
{
|
|
11190
|
+
"id": "20cf1adf4154",
|
|
11191
|
+
"surface": "builders-hall",
|
|
11192
|
+
"text": "Outside access could not be read just now.",
|
|
11193
|
+
"file": "modules/hall-ui/public/government-access.js",
|
|
11194
|
+
"line": 72,
|
|
11195
|
+
"origin": "js-markup",
|
|
11196
|
+
"confidence": "certain"
|
|
11197
|
+
},
|
|
11152
11198
|
{
|
|
11153
11199
|
"id": "d89d1923ecf9",
|
|
11154
11200
|
"surface": "builders-hall",
|
|
@@ -16630,6 +16676,15 @@
|
|
|
16630
16676
|
"origin": "html-text",
|
|
16631
16677
|
"confidence": "certain"
|
|
16632
16678
|
},
|
|
16679
|
+
{
|
|
16680
|
+
"id": "c6d830ca9e08",
|
|
16681
|
+
"surface": "builders-hall",
|
|
16682
|
+
"text": "Who holds the keys outside the project, so a blocker that needs one reaches them. This is a record of who to ask: it grants nothing here and stores no password or token.",
|
|
16683
|
+
"file": "modules/hall-ui/public/government.html",
|
|
16684
|
+
"line": 124,
|
|
16685
|
+
"origin": "html-text",
|
|
16686
|
+
"confidence": "certain"
|
|
16687
|
+
},
|
|
16633
16688
|
{
|
|
16634
16689
|
"id": "045c629729b7",
|
|
16635
16690
|
"surface": "builders-hall",
|
|
@@ -3264,5 +3264,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
3264
3264
|
The lifecycle feed and claim gate apply it. Additive, so MINOR.
|
|
3265
3265
|
1.24.1 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3266
3266
|
landed since 1.24.0 with no explicit bump. run 40985289858. (task 1002620)
|
|
3267
|
+
1.24.2 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3268
|
+
landed since 1.24.1 with no explicit bump. run 41000649913. (task 1002620)
|
|
3269
|
+
1.24.3 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3270
|
+
landed since 1.24.2 with no explicit bump. run 41001671514. (task 1002620)
|
|
3267
3271
|
---------------------------------------------------------------------------
|
|
3268
3272
|
```
|
package/docs/page-inventory.json
CHANGED
|
@@ -611,7 +611,8 @@
|
|
|
611
611
|
"modules/hall-ui/public/palette.js",
|
|
612
612
|
"modules/hall-ui/public/hall-kit.js",
|
|
613
613
|
"modules/hall-ui/public/board-lib.js",
|
|
614
|
-
"modules/hall-ui/public/government.js"
|
|
614
|
+
"modules/hall-ui/public/government.js",
|
|
615
|
+
"modules/hall-ui/public/government-access.js"
|
|
615
616
|
],
|
|
616
617
|
"states_files": [
|
|
617
618
|
"modules/hall-ui/public/government.states.json"
|
package/docs/page-readings.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"adr": "0341 D3",
|
|
6
6
|
"reread": "node scripts/bongos/page-reader.js --stale",
|
|
7
7
|
"how": ["Generated by node scripts/bongos/page-reader.js (BV2.TW04, task 1004315; ADR 0341 D3). Do not hand-edit.","One entry per page of docs/page-inventory.json. Lines are in page order: the default state first, and a line only another state shows sits where that state shows it, with its state named.","placement: placed = a docs/copy-registry.json row renders it (file, line, string_id); shared = shell text every page of the surface carries (top bar, sidebar, footer), with its row when the registry has one; unplaced = the registry cannot place it (a rewrite becomes an engineer task, ADR 0341 D4).","text keeps {…} where the registry row has a hole, or where a value the page read from its API was filled in. A string that is only such data is counted under omitted.data, not listed.","reading_hash is over the non-shared lines (key, section, text); files_hash is over the page's inventory files. --check compares files_hash only and never opens a browser.","Rendered through the hall-preview harness (hall) and the ui-design kit stub (landing, status), at 1280x800 with the clock pinned, so a reading is the fixture world's page."],
|
|
8
|
-
"counts": {"pages":48,"lines":
|
|
8
|
+
"counts": {"pages":48,"lines":5456,"placed":1683,"shared":427,"unplaced":3346,"omitted_data":3731},
|
|
9
9
|
"pages": [
|
|
10
10
|
{
|
|
11
11
|
"id": "builders:ai-studio",
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
"surface": "builders",
|
|
161
161
|
"title": "Blockers",
|
|
162
162
|
"states_read": ["default"],
|
|
163
|
-
"files_hash": "
|
|
163
|
+
"files_hash": "439934ddd9d1a4d2",
|
|
164
164
|
"reading_hash": "c393e54845d545ee",
|
|
165
165
|
"counts": {"lines":34,"placed":14,"shared":8,"unplaced":12},
|
|
166
166
|
"omitted": {"data":49},
|
|
@@ -271,7 +271,7 @@
|
|
|
271
271
|
"surface": "builders",
|
|
272
272
|
"title": "The city",
|
|
273
273
|
"states_read": ["city","fullscreen","switched","focus","pins","living","card","card-ask"],
|
|
274
|
-
"files_hash": "
|
|
274
|
+
"files_hash": "6a8a96e1f9f6084a",
|
|
275
275
|
"reading_hash": "77470c4eb3047a05",
|
|
276
276
|
"counts": {"lines":43,"placed":10,"shared":8,"unplaced":25},
|
|
277
277
|
"omitted": {"data":17},
|
|
@@ -327,7 +327,7 @@
|
|
|
327
327
|
"surface": "builders",
|
|
328
328
|
"title": "Collab",
|
|
329
329
|
"states_read": ["board","out"],
|
|
330
|
-
"files_hash": "
|
|
330
|
+
"files_hash": "2e20ca6774af82fc",
|
|
331
331
|
"reading_hash": "71803b40b959a9b9",
|
|
332
332
|
"counts": {"lines":80,"placed":31,"shared":7,"unplaced":42},
|
|
333
333
|
"omitted": {"data":21},
|
|
@@ -1456,10 +1456,10 @@
|
|
|
1456
1456
|
"surface": "builders",
|
|
1457
1457
|
"title": "Government",
|
|
1458
1458
|
"states_read": ["constitution","out","permissions","board","constitution-tab"],
|
|
1459
|
-
"files_hash": "
|
|
1460
|
-
"reading_hash": "
|
|
1461
|
-
"counts": {"lines":
|
|
1462
|
-
"omitted": {"data":
|
|
1459
|
+
"files_hash": "25c1dc0003420a7c",
|
|
1460
|
+
"reading_hash": "18d8e460088c2550",
|
|
1461
|
+
"counts": {"lines":63,"placed":24,"shared":8,"unplaced":31},
|
|
1462
|
+
"omitted": {"data":274},
|
|
1463
1463
|
"notes": ["permissions: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","board: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","constitution-tab: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood"],
|
|
1464
1464
|
"lines": [
|
|
1465
1465
|
{"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
|
|
@@ -1503,19 +1503,28 @@
|
|
|
1503
1503
|
{"key":"L0039","section":"Assignments","text":"{…} · via rank","placement":"unplaced","occurrences":2},
|
|
1504
1504
|
{"key":"L0040","section":"Assignments","text":"rank","placement":"unplaced","occurrences":3},
|
|
1505
1505
|
{"key":"L0041","section":"Assignments","text":"Remove","placement":"unplaced"},
|
|
1506
|
-
{"key":"L0042","section":"
|
|
1507
|
-
{"key":"L0043","section":"
|
|
1508
|
-
{"key":"L0044","section":"
|
|
1509
|
-
{"key":"L0045","section":"
|
|
1510
|
-
{"key":"L0046","section":"
|
|
1511
|
-
{"key":"L0047","section":"
|
|
1512
|
-
{"key":"L0048","section":"
|
|
1513
|
-
{"key":"L0049","section":"
|
|
1514
|
-
{"key":"L0050","section":"
|
|
1515
|
-
{"key":"L0051","section":"
|
|
1516
|
-
{"key":"L0052","section":"
|
|
1517
|
-
{"key":"L0053","section":"
|
|
1518
|
-
{"key":"L0054","section":"
|
|
1506
|
+
{"key":"L0042","section":"Outside access","text":"Outside access","placement":"placed","file":"modules/hall-ui/public/government.html","line":123,"string_id":"8b1e7aae1e5f"},
|
|
1507
|
+
{"key":"L0043","section":"Outside access","text":"Who holds the keys outside the project, so a blocker that needs one reaches them. This is a record of who to ask: it grants nothing here and stores no password or token.","placement":"placed","file":"modules/hall-ui/public/government.html","line":124,"string_id":"c6d830ca9e08"},
|
|
1508
|
+
{"key":"L0044","section":"Outside access","text":"Builder id","placement":"placed","file":"modules/hall-ui/public/government.html","line":107,"string_id":"08bfcc9198ba"},
|
|
1509
|
+
{"key":"L0045","section":"Outside access","text":"e.g. 95","placement":"unplaced","attr":"placeholder"},
|
|
1510
|
+
{"key":"L0046","section":"Outside access","text":"Access","placement":"unplaced"},
|
|
1511
|
+
{"key":"L0047","section":"Outside access","text":"Record","placement":"unplaced"},
|
|
1512
|
+
{"key":"L0048","section":"Outside access","text":"Remove","placement":"unplaced","occurrences":2},
|
|
1513
|
+
{"key":"L0049","section":"Outside access","text":"Nobody recorded — it falls to the owner","placement":"placed","file":"modules/hall-ui/public/government-access.js","line":35,"string_id":"380b924cd4a0","occurrences":4},
|
|
1514
|
+
{"key":"L0050","section":"Outside access","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232"},
|
|
1515
|
+
{"key":"L0051","section":"Machine principals","text":"Machine principals","placement":"placed","file":"modules/hall-ui/public/government.html","line":140,"string_id":"06b4ede3fb58"},
|
|
1516
|
+
{"key":"L0052","section":"Machine principals","text":"Capabilities held by a machine identity, never by a person or a rank. Shown for completeness; nothing here can be granted.","placement":"placed","file":"modules/hall-ui/public/government.html","line":141,"string_id":"084eb64bce72"},
|
|
1517
|
+
{"key":"L0053","section":"Machine principals","text":"holds","placement":"unplaced","occurrences":2},
|
|
1518
|
+
{"key":"L0054","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":516,"string_id":"1883ad7f07fc"},
|
|
1519
|
+
{"key":"L0055","section":"Machine principals","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
|
|
1520
|
+
{"key":"L0056","section":"What are you doing now?","text":"What are you doing now?","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":671,"string_id":"60853319f290"},
|
|
1521
|
+
{"key":"L0057","section":"What are you doing now?","text":"Pick one. You can switch any time from the top bar.","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":672,"string_id":"4f87d5b17b54"},
|
|
1522
|
+
{"key":"L0058","section":"What are you doing now?","text":"Building","placement":"unplaced"},
|
|
1523
|
+
{"key":"L0059","section":"What are you doing now?","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":3},
|
|
1524
|
+
{"key":"L0060","section":"What are you doing now?","text":"Artistry","placement":"unplaced"},
|
|
1525
|
+
{"key":"L0061","section":"What are you doing now?","text":"Ideating","placement":"unplaced"},
|
|
1526
|
+
{"key":"L0062","section":"What are you doing now?","text":"Turn thoughts into ideas.","placement":"unplaced"},
|
|
1527
|
+
{"key":"L0063","section":"What are you doing now?","text":"Ask me again next session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":675,"string_id":"fa86bf403775"}
|
|
1519
1528
|
]
|
|
1520
1529
|
},
|
|
1521
1530
|
{
|
|
@@ -3361,10 +3370,10 @@
|
|
|
3361
3370
|
"surface": "builders",
|
|
3362
3371
|
"title": "The street",
|
|
3363
3372
|
"states_read": ["street","fullscreen","card","switched","focus","here","inside-rules","inside-disputes","inside-people","inside-planning","inside-automation","inside-review","inside-release","inside-treasury","floor","amend","district","desk","desk-facts","desk-quiet","desk-people-builders","desk-people-tier","desk-disputes","desk-automation-goals","desk-release-core","desk-rules","desk-rules-category","desk-planning-priorities","desk-planning-ideas","desk-planning-blockers","pins","pins-pager","living","deck","deck-treasury","sitting","object","voted","admission","settled","blocker","blocker-more","report","report-more","core","core-more","recheck","recheck-more","idea","idea-more","queue","queue-more","automation","automation-more"],
|
|
3364
|
-
"files_hash": "
|
|
3365
|
-
"reading_hash": "
|
|
3373
|
+
"files_hash": "6180e15ad9dcf4d6",
|
|
3374
|
+
"reading_hash": "b5cd1724efa21f28",
|
|
3366
3375
|
"counts": {"lines":650,"placed":75,"shared":8,"unplaced":567},
|
|
3367
|
-
"omitted": {"data":
|
|
3376
|
+
"omitted": {"data":553},
|
|
3368
3377
|
"notes": ["sitting: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","object: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"board:47\"]); read as it stood","voted: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","admission: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","settled: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","blocker: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"blockers:11\"]); read as it stood","blocker-more: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"blockers:11\"]); read as it stood","report: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"redteam_reports:4\"]); read as it stood","report-more: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"redteam_reports:4\"]); read as it stood","core: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"core_update:1.21.20\"]); read as it stood","core-more: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"core_update:1.21.20\"]); read as it stood","recheck: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"module_rechecks:7\"]); read as it stood","recheck-more: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"module_rechecks:7\"]); read as it stood","idea: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"board:41\"]); read as it stood","idea-more: an action failed (page.evaluate: Error: dispatchClick: nothing matches .street-pin[data-matter=\"board:41\"]); read as it stood"],
|
|
3369
3378
|
"lines": [
|
|
3370
3379
|
{"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
|
|
@@ -3588,7 +3597,7 @@
|
|
|
3588
3597
|
{"key":"L0219","section":"Spending matters","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","state":"inside-treasury"},
|
|
3589
3598
|
{"key":"L0220","section":"Spending matters","text":"{…} from the reserve?","placement":"unplaced","state":"inside-treasury"},
|
|
3590
3599
|
{"key":"L0221","section":"Spending matters","text":"{…} · today","placement":"unplaced","state":"inside-treasury"},
|
|
3591
|
-
{"key":"L0222","section":"Spending matters","text":"
|
|
3600
|
+
{"key":"L0222","section":"Spending matters","text":"7 builders earned 5,5… · today","placement":"unplaced","state":"inside-treasury"},
|
|
3592
3601
|
{"key":"L0223","section":"Spending matters","text":"{…} · 4w","placement":"unplaced","state":"inside-treasury","occurrences":2},
|
|
3593
3602
|
{"key":"L0224","section":"Spending matters","text":"the record","placement":"placed","file":"modules/hall-ui/public/street.html","line":192,"string_id":"4bde7b562cf4","state":"inside-treasury"},
|
|
3594
3603
|
{"key":"L0225","section":"Spending matters","text":"1 matter on the docket · 16 on the {…}","placement":"unplaced","state":"inside-treasury"},
|
|
@@ -3823,7 +3832,7 @@
|
|
|
3823
3832
|
{"key":"L0454","section":"Priorities","text":"standing law","placement":"unplaced","state":"desk-planning-priorities"},
|
|
3824
3833
|
{"key":"L0455","section":"Waiting on {…}","text":"Waiting on {…}","placement":"placed","file":"modules/hall-ui/public/goals-lib.js","line":91,"string_id":"b18832e219dc","state":"inside-planning"},
|
|
3825
3834
|
{"key":"L0456","section":"Waiting on {…}","text":"9 waiting · oldest 3 weeks","placement":"unplaced","state":"inside-planning"},
|
|
3826
|
-
{"key":"L0457","section":"Waiting on {…}","text":"waiting","placement":"placed","file":"modules/hall-ui/public/work.js","line":
|
|
3835
|
+
{"key":"L0457","section":"Waiting on {…}","text":"waiting","placement":"placed","file":"modules/hall-ui/public/work.js","line":438,"string_id":"8186b562553a","state":"inside-planning"},
|
|
3827
3836
|
{"key":"L0458","section":"Waiting on {…}","text":"on {…}","placement":"unplaced","state":"inside-planning"},
|
|
3828
3837
|
{"key":"L0459","section":"Waiting on {…}","text":"WA","placement":"unplaced","state":"inside-planning"},
|
|
3829
3838
|
{"key":"L0460","section":"Waiting on {…}","text":"Working area 2…","placement":"unplaced","state":"inside-planning"},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// modules/government/docket.js).
|
|
6
6
|
//
|
|
7
7
|
// WHY. Inside the Treasury building three floors are the project's real
|
|
8
|
-
//
|
|
8
|
+
// lines — credits earned for shipped work, the AI grader, and hosting —
|
|
9
9
|
// and its record drawers are those same lines month by month. They come from
|
|
10
10
|
// the two ledgers this module owns (credit_log, cost_log) through ONE bounded
|
|
11
11
|
// read, cost.treasuryMonths. The ledgers are already published unauthenticated
|
|
@@ -28,22 +28,28 @@ function usd(n) {
|
|
|
28
28
|
const v = Math.round(Number(n) || 0);
|
|
29
29
|
return `$${v.toLocaleString('en-US')}`;
|
|
30
30
|
}
|
|
31
|
+
// Credits are a contribution meter, not money (ADR 0385, ADR 0387): the rewards
|
|
32
|
+
// line counts them and never wears a $ sign (task 1005006).
|
|
33
|
+
function credits(n) {
|
|
34
|
+
const v = Math.round(Number(n) || 0);
|
|
35
|
+
return `${v.toLocaleString('en-US')} ${v === 1 ? 'credit' : 'credits'}`;
|
|
36
|
+
}
|
|
31
37
|
function monthKey(now) { const d = new Date(now); return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`; }
|
|
32
38
|
function monthWord(key) { const m = Number(String(key).slice(5, 7)); return MONTHS[m - 1] || String(key); }
|
|
33
39
|
|
|
34
40
|
// One spending line's floor from the month rows. Pure.
|
|
35
|
-
function lineFloor(months, now, field, { what, meta }) {
|
|
41
|
+
function lineFloor(months, now, field, { what, meta, fmt = usd }) {
|
|
36
42
|
const rows = Array.isArray(months) ? months : [];
|
|
37
43
|
const cur = rows.find((r) => r.month === monthKey(now));
|
|
38
44
|
const prev = rows.find((r) => r.month < monthKey(now));
|
|
39
45
|
const v = cur ? Number(cur[field]) || 0 : 0;
|
|
40
46
|
const lines = [[what, meta]];
|
|
41
|
-
if (prev) lines.push([`${
|
|
42
|
-
return { count:
|
|
47
|
+
if (prev) lines.push([`${fmt(prev[field])} in ${monthWord(prev.month)}.`, 'last month']);
|
|
48
|
+
return { count: fmt(v), line: `${fmt(v)} this month`, lines, hot: false };
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
function rewardsFloor(months, now) {
|
|
46
|
-
const f = lineFloor(months, now, 'rewards_credits', { what: '
|
|
52
|
+
const f = lineFloor(months, now, 'rewards_credits', { what: 'Credits earned for shipped work. They count contribution; they are not money.', meta: 'each ship', fmt: credits });
|
|
47
53
|
const cur = (months || []).find((r) => r.month === monthKey(now));
|
|
48
54
|
const n = cur ? cur.rewarded_builders : 0;
|
|
49
55
|
return { ...f, line: `${f.count} this month · ${n} ${n === 1 ? 'builder' : 'builders'}` };
|
|
@@ -56,7 +62,7 @@ function treasuryHistory(months) {
|
|
|
56
62
|
const out = [];
|
|
57
63
|
for (const r of months || []) {
|
|
58
64
|
const at = `${r.month}-01T00:00:00.000Z`;
|
|
59
|
-
if (r.rewards_credits > 0) out.push({ id: `rewards:${r.month}`, title:
|
|
65
|
+
if (r.rewards_credits > 0) out.push({ id: `rewards:${r.month}`, title: `${r.rewarded_builders} ${r.rewarded_builders === 1 ? 'builder' : 'builders'} earned ${credits(r.rewards_credits)}`, at, outcome: 'rewards' });
|
|
60
66
|
if (r.grading_usd > 0) out.push({ id: `grading:${r.month}`, title: `AI grading cost ${usd(r.grading_usd)}`, at, outcome: 'grading' });
|
|
61
67
|
if (r.hosting_usd > 0) out.push({ id: `hosting:${r.month}`, title: `Hosting cost ${usd(r.hosting_usd)}`, at, outcome: 'hosting' });
|
|
62
68
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// modules/government/access-routes.js — the handlers behind the three ACCESS HOLDERS
|
|
4
|
+
// routes (task 1005000). The routes themselves — path, permission gate and pin — are
|
|
5
|
+
// declared in routes/government.js, where route-rank-check reads them; only the bodies
|
|
6
|
+
// live here, so the router file stays under the size ratchet.
|
|
7
|
+
//
|
|
8
|
+
// GET /government/access (board.vote.cast) — read
|
|
9
|
+
// POST /government/access/:accessKey/holders (government.manage) — record
|
|
10
|
+
// DELETE /government/access/:accessKey/holders/:builderId (government.manage) — remove
|
|
11
|
+
//
|
|
12
|
+
// ⚠ A record of who to ask, never authority (access.js). Not act-alone routes: they
|
|
13
|
+
// record a fact about the world outside the project; they decide nothing a sitting
|
|
14
|
+
// votes on.
|
|
15
|
+
|
|
16
|
+
const access = require('./access');
|
|
17
|
+
|
|
18
|
+
// deps: { db, log, parseId, validateOrRespond } — the router's own, passed in so a
|
|
19
|
+
// test that stubs the db by property reaches these handlers too.
|
|
20
|
+
function accessHandlers({ db, log, parseId, validateOrRespond }) {
|
|
21
|
+
const keyOf = (req, res) => {
|
|
22
|
+
const key = String(req.params.accessKey || '');
|
|
23
|
+
if (access.isAccessKey(key)) return key;
|
|
24
|
+
res.fail('unknown_access', { status: 400, message: `Name one of: ${access.KEYS.join(', ')}.` });
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
async function read(req, res) {
|
|
29
|
+
try {
|
|
30
|
+
res.json({ access: access.accessView(await db.listAccessHolders()) });
|
|
31
|
+
} catch (err) {
|
|
32
|
+
log.error('[gds] GET /government/access', err);
|
|
33
|
+
res.fail('access_read_failed', { status: 500, message: 'internal error' });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function grant(req, res) {
|
|
38
|
+
if (validateOrRespond(req, res, { builder_id: { required: true, type: 'integer', min: 1 } })) return;
|
|
39
|
+
const key = keyOf(req, res);
|
|
40
|
+
if (key === null) return;
|
|
41
|
+
const builderId = req.body.builder_id;
|
|
42
|
+
try {
|
|
43
|
+
const who = await db.getActiveBuilder(builderId);
|
|
44
|
+
if (!who) return res.fail('builder_not_found', { status: 404, message: 'No active builder with that id.' });
|
|
45
|
+
const added = await db.grantAccess(key, builderId, req.builder.id);
|
|
46
|
+
res.status(added ? 201 : 200).json({ ok: true, access_key: key, builder_id: String(builderId), added });
|
|
47
|
+
} catch (err) {
|
|
48
|
+
log.error('[gds] POST /government/access/:accessKey/holders', err);
|
|
49
|
+
res.fail('access_grant_failed', { status: 500, message: 'internal error' });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function revoke(req, res) {
|
|
54
|
+
const key = keyOf(req, res);
|
|
55
|
+
if (key === null) return;
|
|
56
|
+
const builderId = parseId(req, res, { param: 'builderId', code: 'bad_builder_id', positiveInt: true });
|
|
57
|
+
if (builderId === null) return;
|
|
58
|
+
try {
|
|
59
|
+
const removed = await db.revokeAccess(key, builderId);
|
|
60
|
+
res.json({ ok: true, access_key: key, builder_id: String(builderId), removed });
|
|
61
|
+
} catch (err) {
|
|
62
|
+
log.error('[gds] DELETE /government/access/:accessKey/holders/:builderId', err);
|
|
63
|
+
res.fail('access_revoke_failed', { status: 500, message: 'internal error' });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return { read, grant, revoke };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { accessHandlers };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// modules/government/access.js — ACCESS HOLDERS: who holds the keys that live OUTSIDE
|
|
4
|
+
// Bongos, so a blocker that needs one reaches the person who has it (task 1005000,
|
|
5
|
+
// goal 1000111).
|
|
6
|
+
//
|
|
7
|
+
// WHY. Some blockers can only be cleared by whoever holds access no rank or Lead
|
|
8
|
+
// models: the GitHub repository's admin (token scopes, branch protection, the App's
|
|
9
|
+
// permissions), the server, the domain's DNS, the hosting account, package publishing,
|
|
10
|
+
// payments. An Archon in Bongos may not hold the GitHub admin, and a Lead never does.
|
|
11
|
+
// It lived only in prose (docs/credentials.md "account logins the owner holds") and in
|
|
12
|
+
// blocker text — blocker 1000199, the publish token missing GitHub's `workflow` scope,
|
|
13
|
+
// could only be filed to "the owner". The builder's words: repo owner is a category of
|
|
14
|
+
// blockers that go beyond normality.
|
|
15
|
+
//
|
|
16
|
+
// WHAT IT IS. A fixed vocabulary of outside-access keys (ACCESS, extendable here and in
|
|
17
|
+
// the migration's CHECK together), a record of which builders hold each
|
|
18
|
+
// (government_access_holders, written by the owner only), and a seat, `access:<key>`,
|
|
19
|
+
// that an ask can wait on. routing.js resolves that seat to the recorded holders, and
|
|
20
|
+
// to the owner when nobody is recorded — the same fall every other seat takes.
|
|
21
|
+
//
|
|
22
|
+
// ⚠ A RECORD OF WHO TO ASK, NEVER AN AUTHORITY GRANT. Holding github-admin here unlocks
|
|
23
|
+
// no Bongos route and no rank: this module is not read by requireRank, the permission
|
|
24
|
+
// resolver, or any gate, and an access key is not a permission atom. No secret is
|
|
25
|
+
// stored either — the row says WHO holds an access, never a credential or a token.
|
|
26
|
+
//
|
|
27
|
+
// PURE: no db.
|
|
28
|
+
|
|
29
|
+
const ACCESS = Object.freeze([
|
|
30
|
+
// name: how the seat reads after "waits on the"; needs: what a blocker on it needs.
|
|
31
|
+
Object.freeze({ key: 'github-admin', name: 'repo owner', needs: 'repo-owner access', what: 'Admin on the GitHub repository: token scopes, branch protection, the GitHub App.' }),
|
|
32
|
+
Object.freeze({ key: 'server-ssh', name: 'server access', needs: 'server access', what: 'A login on the server the project runs on.' }),
|
|
33
|
+
Object.freeze({ key: 'dns', name: 'domain settings', needs: 'access to the domain settings', what: 'The DNS account for the project\'s domain.' }),
|
|
34
|
+
Object.freeze({ key: 'hosting', name: 'hosting account', needs: 'access to the hosting account', what: 'The account that pays for and runs the project\'s servers.' }),
|
|
35
|
+
Object.freeze({ key: 'npm-publish', name: 'package publishing', needs: 'package publishing rights', what: 'Publishing rights for the project\'s packages.' }),
|
|
36
|
+
Object.freeze({ key: 'payments', name: 'payments', needs: 'access to payments', what: 'The account money moves through.' }),
|
|
37
|
+
]);
|
|
38
|
+
const KEYS = Object.freeze(ACCESS.map((a) => a.key));
|
|
39
|
+
const isAccessKey = (k) => KEYS.includes(String(k || ''));
|
|
40
|
+
const byKey = (k) => ACCESS.find((a) => a.key === k) || null;
|
|
41
|
+
|
|
42
|
+
// The seat grammar's access half, for asks.js SEAT and the migration's CHECK.
|
|
43
|
+
const SEAT_PART = `access:(${KEYS.join('|')})`;
|
|
44
|
+
|
|
45
|
+
// "the repo owner" — how the seat reads after "waits on".
|
|
46
|
+
function accessLabel(key) {
|
|
47
|
+
const a = byKey(key);
|
|
48
|
+
return a ? `the ${a.name}` : 'the owner';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// "needs repo-owner access" — how a blocker on this seat reads under its holder.
|
|
52
|
+
function needsWords(key) {
|
|
53
|
+
const a = byKey(key);
|
|
54
|
+
return a ? `needs ${a.needs}` : 'needs outside access';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// The holders read as the seat resolver wants them: { key: [{ builder_id, github_login, display_name }] }.
|
|
58
|
+
function holdersByKey(rows) {
|
|
59
|
+
const out = {};
|
|
60
|
+
for (const k of KEYS) out[k] = [];
|
|
61
|
+
for (const r of rows || []) {
|
|
62
|
+
if (r && isAccessKey(r.access_key) && r.builder_id != null) out[r.access_key].push(r);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The read GET /government/access answers: every access, its words, who holds it.
|
|
68
|
+
function accessView(rows) {
|
|
69
|
+
const held = holdersByKey(rows);
|
|
70
|
+
return ACCESS.map((a) => ({
|
|
71
|
+
key: a.key,
|
|
72
|
+
name: a.name,
|
|
73
|
+
// the one display form, for the list and the picker alike
|
|
74
|
+
title: a.name.charAt(0).toUpperCase() + a.name.slice(1),
|
|
75
|
+
what: a.what,
|
|
76
|
+
seat: `access:${a.key}`,
|
|
77
|
+
holders: held[a.key].map((r) => ({
|
|
78
|
+
id: String(r.builder_id),
|
|
79
|
+
login: r.github_login || null,
|
|
80
|
+
name: r.display_name || r.github_login || null,
|
|
81
|
+
since: r.granted_at || null,
|
|
82
|
+
})),
|
|
83
|
+
// nobody recorded: the seat falls to the owner, as every unheld seat does
|
|
84
|
+
falls_to_owner: held[a.key].length === 0,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = { ACCESS, KEYS, SEAT_PART, isAccessKey, accessLabel, needsWords, holdersByKey, accessView };
|