@bongos/core 1.19.1045 → 1.19.1046

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 (78) hide show
  1. package/.bongos-core.json +87 -112
  2. package/docs/adr/0337-the-hub-account-is-the-person-a-hall-account-is-their-seat-in-one-project.md +14 -2
  3. package/docs/adr/README.md +1 -1
  4. package/docs/copy-inventory.md +17 -24
  5. package/docs/copy-registry.json +24 -97
  6. package/docs/file-map.md +2 -3
  7. package/docs/module-api-changelog.md +2 -0
  8. package/docs/recipes/windows-builders.md +1 -1
  9. package/modules/hall-ui/public/atlas.html +1 -1
  10. package/modules/hall-ui/public/blockers.html +1 -1
  11. package/modules/hall-ui/public/board-room.html +1 -1
  12. package/modules/hall-ui/public/collab.css +1 -1
  13. package/modules/hall-ui/public/collab.html +1 -1
  14. package/modules/hall-ui/public/copy-desk.html +1 -1
  15. package/modules/hall-ui/public/deploy.html +1 -1
  16. package/modules/hall-ui/public/diagrams.html +1 -1
  17. package/modules/hall-ui/public/drachmae.html +1 -1
  18. package/modules/hall-ui/public/fleet.html +1 -1
  19. package/modules/hall-ui/public/gate.html +1 -1
  20. package/modules/hall-ui/public/goals.html +1 -1
  21. package/modules/hall-ui/public/government.html +1 -1
  22. package/modules/hall-ui/public/idea.html +1 -1
  23. package/modules/hall-ui/public/ideas.html +1 -1
  24. package/modules/hall-ui/public/index.html +1 -1
  25. package/modules/hall-ui/public/modules.html +1 -1
  26. package/modules/hall-ui/public/primer.html +1 -1
  27. package/modules/hall-ui/public/profile.html +1 -1
  28. package/modules/hall-ui/public/project-settings.html +1 -1
  29. package/modules/hall-ui/public/ranks.html +1 -1
  30. package/modules/hall-ui/public/roadmap.html +1 -1
  31. package/modules/hall-ui/public/{people.css → roster.css} +7 -11
  32. package/modules/hall-ui/public/roster.html +5 -5
  33. package/modules/hall-ui/public/roster.js +6 -7
  34. package/modules/hall-ui/public/roster.states.json +1 -1
  35. package/modules/hall-ui/public/sessions.html +1 -1
  36. package/modules/hall-ui/public/settings.html +2 -2
  37. package/modules/hall-ui/public/settings.js +2 -2
  38. package/modules/hall-ui/public/shell.js +3 -10
  39. package/modules/hall-ui/public/studio.html +1 -1
  40. package/modules/hall-ui/public/style.css +2 -9
  41. package/modules/hall-ui/public/task.html +1 -1
  42. package/modules/hall-ui/public/watch.html +1 -1
  43. package/modules/hall-ui/public/work.html +1 -1
  44. package/modules/hall-ui/records/builders-roster.md +1 -1
  45. package/modules/hall-ui/records/roster-and-ledger.md +2 -2
  46. package/modules/platform-identity/account-visibility.js +3 -3
  47. package/modules/platform-identity/platform-identity.js +2 -2
  48. package/modules/platform-identity/routes/profile.js +1 -1
  49. package/modules/platform-identity/routes/sso.js +4 -3
  50. package/modules/platform-identity/scouting-authz.js +2 -2
  51. package/modules/platform-identity/tests/platform-identity.mjs +1 -1
  52. package/package-lock.json +2 -2
  53. package/package.json +1 -1
  54. package/release-notes.json +6 -0
  55. package/src/bongos/auth.js +9 -24
  56. package/src/bongos/serve-internal.js +13 -19
  57. package/src/module-api.js +1 -1
  58. package/tests/account_privacy_flags.mjs +1 -1
  59. package/tests/auth_resolve_failure.mjs +6 -6
  60. package/tests/core_upgrade_owner_door.mjs +1 -1
  61. package/tests/edit_hints.mjs +8 -8
  62. package/tests/effective_visibility_predicate.mjs +1 -1
  63. package/tests/government_parity.mjs +1 -1
  64. package/tests/hall_builders_page_pass.mjs +2 -2
  65. package/tests/hall_nav.mjs +8 -8
  66. package/tests/hall_page_gate_map.mjs +14 -11
  67. package/tests/hall_roster_world.mjs +47 -78
  68. package/tests/module_contributions.mjs +0 -1
  69. package/tests/nav_permission_atoms.mjs +1 -1
  70. package/tests/{scouting_page_gate.mjs → page_gate_second_door.mjs} +34 -29
  71. package/tests/profile_rollup_consent.mjs +4 -4
  72. package/tests/profile_route.mjs +3 -26
  73. package/tests/scouting_owner_access_and_reach.mjs +4 -8
  74. package/modules/hall-ui/public/people.html +0 -79
  75. package/modules/hall-ui/public/people.js +0 -321
  76. package/modules/hall-ui/public/people.states.json +0 -89
  77. package/tests/people_directory_clip.mjs +0 -269
  78. package/tests/people_name_only.mjs +0 -263
@@ -212,7 +212,7 @@ caught a real bug during task 1003548, so read its assertion before blaming the
212
212
 
213
213
  ## CRLF: a multi-line find silently misses, and a whole-file diff is usually line endings
214
214
 
215
- - Several hall files (`people.css`, `people.html`, `style.css`, the privacy spec) and every `.claude/skills/*/SKILL.md` are CRLF; `scripts/gds/*.js` and the tests are LF. An exact-string patch must detect the file's EOL before joining lines (`text.includes('\r\n') ? '\r\n' : '\n'`), or the find matches nothing and the edit is a silent no-op (session log 2026-08-24).
215
+ - Several hall files (`roster.css`, `roster.html`, `style.css`, the privacy spec) and every `.claude/skills/*/SKILL.md` are CRLF; `scripts/gds/*.js` and the tests are LF. An exact-string patch must detect the file's EOL before joining lines (`text.includes('\r\n') ? '\r\n' : '\n'`), or the find matches nothing and the edit is a silent no-op (session log 2026-08-24).
216
216
  - A `git diff --stat` that touches every line of a file you barely edited is an EOL flip — check with `git diff --stat --ignore-cr-at-eol`, and restore the original EOL before committing.
217
217
  - **`copy-inventory.js --check` no longer reds on line endings alone** (task 1003619). It used to: the generator emits LF and the check byte-compared that against a CRLF worktree file, so `/ship-check` showed one permanent red line on every Windows checkout while the committed content was already correct — and a builder who "fixed" it committed a whole-file CRLF diff. `docs/copy-inventory.md` is now pinned `text eol=lf` in `.gitattributes` (its `.json` sibling always was, via `*.json`), and the check compares EOL-blind so an already-CRLF worktree passes without a re-clone. If it reports STALE now, the content really is stale — regenerate, don't reach for `--ignore-cr-at-eol`. Since task 1003981 `*.md` IS pinned repo-wide (`*.md text eol=lf`), so a fresh clone gets LF markdown everywhere and a markdown reader no longer has to be CRLF-aware to be correct. An EXISTING Windows checkout keeps its CRLF copies until git rewrites them — the clean filter still normalises to LF on add, so `git status` stays quiet and nothing is broken; to convert in place, `git rm --cached -r . && git reset --hard`.
218
218
  - **A freshness check compares CONTENT, so route it through `sameContent()`** (`scripts/gds/gen-freshness.js`) rather than `===` on file bytes. A pin is the wrong lever on its own: regenerating never clears a byte-wise red, because the write lands LF and git converts it back on the next checkout. `tests/gen_freshness.mjs` enforces this for the four gated generators; `tests/api_client.mjs` was outside that guard and reported the client STALE forever on Windows until task 1003529 (`index.d.ts` and `README.md` are the two generated client files with no `eol=lf` pin).
@@ -91,7 +91,7 @@
91
91
 
92
92
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
93
93
 
94
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
94
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
95
95
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
96
96
  <script src="/builders/palette.js" defer></script>
97
97
  <script src="/builders/atlas.js?v=2026-09-02-index" defer></script>
@@ -50,7 +50,7 @@
50
50
 
51
51
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
52
52
  chrome exists before the page script runs. -->
53
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
53
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
54
54
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
55
55
  <script src="/builders/palette.js" defer></script>
56
56
  <!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
@@ -60,7 +60,7 @@
60
60
 
61
61
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
62
62
 
63
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
63
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
64
64
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
65
65
  <script src="/builders/palette.js" defer></script>
66
66
  <script src="/builders/dom-utils.js?v=2026-06-16-board"></script>
@@ -108,7 +108,7 @@
108
108
 
109
109
  /* ---- the face -----------------------------------------------------------------
110
110
  A row leads with WHO: a 36px disc, the picture when the server sent one, the
111
- initial on the glass when it did not (people.css's .dir-avatar, at the row's
111
+ initial on the glass when it did not (roster.css's .dir-avatar, at the row's
112
112
  size). A craft ask wears the craft's letter in the label face, so it never
113
113
  passes for a person. Decorative — the name beside it is the door. */
114
114
  .cb-face {
@@ -148,7 +148,7 @@
148
148
 
149
149
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
150
150
 
151
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
151
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
152
152
  <script src="/builders/palette.js" defer></script>
153
153
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
154
154
  <script src="/builders/collab-lib.js?v=2026-09-24-archive"></script>
@@ -177,7 +177,7 @@
177
177
 
178
178
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
179
179
 
180
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
180
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
181
181
  <script src="/builders/palette.js" defer></script>
182
182
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
183
183
  <script src="/builders/hall-kit.js"></script>
@@ -69,7 +69,7 @@
69
69
 
70
70
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
71
71
 
72
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
72
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
73
73
  <script src="/builders/palette.js" defer></script>
74
74
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
75
75
  <script src="/builders/hall-kit.js"></script>
@@ -97,7 +97,7 @@
97
97
 
98
98
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
99
99
  time so the chrome exists before the deferred page scripts execute. -->
100
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
100
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
101
101
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
102
102
  <script src="/builders/palette.js" defer></script>
103
103
  <script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
@@ -98,7 +98,7 @@
98
98
 
99
99
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
100
100
 
101
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
101
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
102
102
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
103
103
  <script src="/builders/palette.js" defer></script>
104
104
  <script src="/builders/md-reader.js?v=2026-09-02-mdreader-2"></script>
@@ -54,7 +54,7 @@
54
54
 
55
55
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
56
56
 
57
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
57
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
58
58
  <script src="/builders/palette.js" defer></script>
59
59
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
60
60
  <script src="/builders/hall-kit.js"></script>
@@ -76,7 +76,7 @@
76
76
  <div id="gate-modal-root"></div>
77
77
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
78
78
 
79
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
79
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
80
80
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
81
81
  <script src="/builders/palette.js" defer></script>
82
82
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -235,7 +235,7 @@
235
235
 
236
236
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
237
237
 
238
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
238
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
239
239
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
240
240
  <script src="/builders/palette.js" defer></script>
241
241
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -134,7 +134,7 @@
134
134
 
135
135
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
136
136
 
137
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
137
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
138
138
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
139
139
  <script src="/builders/palette.js" defer></script>
140
140
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -52,7 +52,7 @@
52
52
 
53
53
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
54
54
 
55
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
55
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
56
56
  <script src="/builders/palette.js" defer></script>
57
57
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib" defer></script>
58
58
  <!-- task-detail.js still owns the #/idea/N and #/blocker/N overlay, so a ref
@@ -225,7 +225,7 @@
225
225
 
226
226
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
227
227
 
228
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
228
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
229
229
  <script src="/builders/palette.js" defer></script>
230
230
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
231
231
  <!-- task 1003069 (R08) — the quick-filing form's routed result links a task
@@ -102,7 +102,7 @@
102
102
  <script src="/builders/brand-apply.js?v=2026-06-27-r75" defer></script>
103
103
  <!-- The app shell (sidebar + top bar + view router). Dependency-free; loaded
104
104
  BEFORE builders.js so the chrome ids exist when events are wired. -->
105
- <script src="/builders/shell.js?v=2026-09-26-swupdate" defer></script>
105
+ <script src="/builders/shell.js?v=2026-09-26-nopeople" defer></script>
106
106
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
107
107
  <script src="/builders/palette.js" defer></script>
108
108
  <!-- task 2166: the shared component kit (window.OTBKit) — pager/ledger/rail.
@@ -80,7 +80,7 @@
80
80
 
81
81
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
82
82
 
83
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
83
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
84
84
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
85
85
  <script src="/builders/palette.js" defer></script>
86
86
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
@@ -115,7 +115,7 @@
115
115
 
116
116
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
117
117
 
118
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
118
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
119
119
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
120
120
  <script src="/builders/palette.js" defer></script>
121
121
  <!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
@@ -187,7 +187,7 @@
187
187
 
188
188
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
189
189
  chrome exists before the page script runs. -->
190
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
190
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
191
191
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
192
192
  <script src="/builders/palette.js" defer></script>
193
193
  <!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
@@ -58,7 +58,7 @@
58
58
 
59
59
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
60
60
 
61
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
61
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
62
62
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
63
63
  <script src="/builders/palette.js" defer></script>
64
64
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -68,7 +68,7 @@
68
68
 
69
69
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
70
70
  chrome exists before the page script runs. -->
71
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
71
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
72
72
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
73
73
  <script src="/builders/palette.js" defer></script>
74
74
  <!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
@@ -41,7 +41,7 @@
41
41
 
42
42
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
43
43
 
44
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
44
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
45
45
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
46
46
  <script src="/builders/palette.js" defer></script>
47
47
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -1,13 +1,11 @@
1
- /* people.css — page-local styles for the cross-project builder directory
2
- (task 1003470, goal 1000081), served at /people — its legacy door /scouting
3
- was deleted in task 1003440 and now 301s here. Only the identity cell lives
4
- here: the
5
- ledger, the filter bar, the pager, the chips and the empty state are the
6
- shell's and the kit's. Tokens are the world's real names — no compat alias. */
1
+ /* roster.css — page-local styles for the Builders page (/roster). The identity
2
+ cell was shared with the cross-project directory at /people until task
3
+ 1003444 deleted that page from the hall; it lives here now. Only the
4
+ identity cell and the place/id cell live here: the ledger, the filter bar,
5
+ the pager and the empty state are the shell's and the kit's. Tokens are the
6
+ world's real names — no compat alias. */
7
7
 
8
- /* The who cell: avatar, then the name over the login. A row that carries an
9
- avatar centres its figures on it, so the numbers line up with the name. */
10
- #people-body .ledger td { vertical-align: middle; }
8
+ /* The who cell: avatar, then the name over the login. */
11
9
  .dir-who { display: inline-flex; align-items: center; gap: 11px; min-width: 0; }
12
10
  .dir-avatar {
13
11
  width: 30px; height: 30px; border-radius: 50%; flex: none;
@@ -33,5 +31,3 @@
33
31
  font-size: 11.5px;
34
32
  color: var(--ink-faint);
35
33
  }
36
- .dir-crafts { display: inline-flex; flex-wrap: wrap; gap: 6px; }
37
- .dir-none { color: var(--ink-faint); }
@@ -9,9 +9,9 @@
9
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
11
  <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
12
- <!-- task 1003441: the identity cell (avatar, name, login) is shared with the
13
- cross-project directory — one definition, both rosters. -->
14
- <link rel="stylesheet" href="/builders/people.css">
12
+ <!-- task 1003441: the identity cell (avatar, name, login). It was shared with
13
+ the cross-project /people page until task 1003444 deleted it. -->
14
+ <link rel="stylesheet" href="/builders/roster.css">
15
15
  </head>
16
16
  <body data-page="roster" data-page-title="Builders">
17
17
 
@@ -25,7 +25,7 @@
25
25
  rewritten by roster.js once the roster has loaded. -->
26
26
  <div class="page-head page-head--board">
27
27
  <h1 class="page-head__h">Builders</h1>
28
- <p class="page-head__sub" id="roster-sub">Who builds on this project, ranked by work shipped. This project's own ledger — unlike the cross-project directory, it lists everyone who builds here.</p>
28
+ <p class="page-head__sub" id="roster-sub">Who builds on this project, ranked by work shipped. This project's own ledger — everyone who builds here is listed.</p>
29
29
  </div>
30
30
 
31
31
  <main id="hall-main">
@@ -50,7 +50,7 @@
50
50
 
51
51
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
52
52
  chrome exists before the page script runs. -->
53
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
53
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
54
54
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
55
55
  <script src="/builders/palette.js" defer></script>
56
56
  <!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
@@ -5,9 +5,9 @@
5
5
  // Community nav group read as one real page plus a link into the home page. It
6
6
  // is a page now, and `/#leaderboard` redirects here (shell.js VIEW_REDIRECTS).
7
7
  //
8
- // PROJECT-OWN, not cross-project. /people is the cross-project directory behind
9
- // `project.curate`; this is the project's own ledger and is deliberately
10
- // ungated, because its one data source — GET /leaderboard
8
+ // PROJECT-OWN, not cross-project: the hall's only builder directory since task
9
+ // 1003444 deleted /people (cross-project discovery is the hub's, ADR 0337). It
10
+ // is deliberately ungated, because its one data source — GET /leaderboard
11
11
  // (modules/economy/routes/leaderboard.js) — is deliberately unauthenticated and
12
12
  // mirrors the public status surface. No visibility predicate is applied and that
13
13
  // is CORRECT: privacy suppresses cross-project surfaces only, so a builder
@@ -77,10 +77,9 @@
77
77
  function httpUrl(u) {
78
78
  return /^https?:\/\//i.test(String(u || '')) ? String(u) : null;
79
79
  }
80
- // The identity cell, shared with /people through people.css. The name opens
81
- // the builder's profile PAGE here: this is a project surface, so a local
82
- // profile id exists — unlike the cross-project directory, which can only
83
- // offer GitHub. Guarded on b.id so a row without one degrades to plain text
80
+ // The identity cell (roster.css). The name opens the builder's profile PAGE:
81
+ // this is a project surface, so a local profile id exists. Guarded on b.id
82
+ // so a row without one degrades to plain text
84
83
  // rather than a broken /profile?id=undefined link (task 1467).
85
84
  function whoHtml(b) {
86
85
  var name = esc(builderName(b));
@@ -1,5 +1,5 @@
1
1
  {
2
- "_": "Builders — this project's OWN roster, ranked by credits earned (task 1003441, goal 1000075). Was the #leaderboard hash view on index.html; /#leaderboard now redirects here. Deliberately UNGATED, because its one data source (GET /leaderboard) is deliberately unauthenticated and mirrors the public status surface — so unlike people.states.json the `out` state below renders the real page rather than a seal. Populated look: the hall-preview harness (scripts/hall-preview/fixtures/leaderboard.json carries thirteen builders with avatars, ranks, karma and tokens).",
2
+ "_": "Builders — this project's OWN roster, ranked by credits earned (task 1003441, goal 1000075). Was the #leaderboard hash view on index.html; /#leaderboard now redirects here. Deliberately UNGATED, because its one data source (GET /leaderboard) is deliberately unauthenticated and mirrors the public status surface — so unlike a gated page's states file the `out` state below renders the real page rather than a seal. Populated look: the hall-preview harness (scripts/hall-preview/fixtures/leaderboard.json carries thirteen builders with avatars, ranks, karma and tokens).",
3
3
  "page": "/builders/roster",
4
4
  "surface": "hall-ui",
5
5
  "stub": {
@@ -99,7 +99,7 @@
99
99
 
100
100
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
101
101
  chrome exists before the page script runs. -->
102
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
102
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
103
103
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
104
104
  <script src="/builders/palette.js" defer></script>
105
105
  <!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
@@ -96,7 +96,7 @@
96
96
  <p class="scroll__lede">
97
97
  Your track record across every project you build on, shown on your
98
98
  public profile. Hiding it takes effect immediately everywhere —
99
- your profile, the People directory, and recruiting views.
99
+ your profile, the recruiting directory, and a recruiter's look-up of one builder.
100
100
  </p>
101
101
  <div id="cross-project-rows"></div>
102
102
  <p class="settings-status" id="cross-project-status" role="status" aria-live="polite"></p>
@@ -436,7 +436,7 @@
436
436
 
437
437
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
438
438
  chrome exists before the page scripts run. -->
439
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
439
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
440
440
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
441
441
  <script src="/builders/palette.js" defer></script>
442
442
  <!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
@@ -490,7 +490,7 @@
490
490
  // GET/PATCH /api/bongos/me/cross-project (platform-identity module — hub only).
491
491
  // One on/off toggle: "show my cross-project record on my public profile".
492
492
  // Enforcement is server-side in the module's read functions, so flipping it
493
- // takes effect immediately on the profile and /people. The section
493
+ // takes effect immediately on the profile and /scouting. The section
494
494
  // reveals ONLY when the module's endpoint answers (404 on a vanilla instance →
495
495
  // stays hidden, no error state). P04 later re-homes this in the Profile rail
496
496
  // group; storage is account-global on the hub (not behavior_prefs).
@@ -562,7 +562,7 @@
562
562
  privacyRow('visibility', 'Public profile page', isPublic ? 'Public' : 'Private', isPublic,
563
563
  'Public means anyone can open your profile page and find you by name. Private hides the page from everyone — including you: it answers "not found" to every visitor, and you read your own record here in Settings instead.', '') +
564
564
  privacyRow('discoverable', 'Discoverable by recruiters', discoverable ? 'On' : 'Off', discoverable,
565
- `Recruiters looking for builders can find you. ${grant}${despitePrivate} Turning this off removes you from both recruiting surfaces — the People directory, and a recruiter's look-up of one builder — straight away.`,
565
+ `Recruiters looking for builders can find you. ${grant}${despitePrivate} Turning this off removes you from both recruiting surfaces — the recruiting directory, and a recruiter's look-up of one builder — straight away.`,
566
566
  follows ? ' <span class="voices__default">· follows your profile setting</span>' : '');
567
567
  }
568
568
 
@@ -92,7 +92,6 @@
92
92
  goals: '<circle cx="9" cy="9" r="6.5"/><circle cx="9" cy="9" r="3.5"/><circle cx="9" cy="9" r="0.8" fill="currentColor"/>',
93
93
  roadmap: '<path d="M3 15.5V3.5l4 2 4-2 4 2v10l-4-2-4 2-4-2Z"/><path d="M7 3.5v10M11 5.5v10"/>',
94
94
  leaderboard: '<path d="M3.5 15.5v-6M9 15.5V3.5m5.5 12v-9"/>',
95
- people: '<circle cx="6.5" cy="6.5" r="2.5"/><path d="M2.5 15c.5-2.4 2-3.7 4-3.7s3.5 1.3 4 3.7"/><circle cx="12.5" cy="7" r="2"/><path d="M12 11.5c1.8.1 3 1.3 3.5 3.3"/>',
96
95
  docs: '<path d="M4 3.5h7l3 3v10H4v-13Z"/><path d="M11 3.5v3h3"/>',
97
96
  // task 1003117 (R06 of goal 1000074): the Studio (artist mode). A sprout —
98
97
  // the zen-garden reading of "a place an artist wants to be", so it does not
@@ -293,15 +292,9 @@
293
292
  // page, so no `view` key. Labelled Builders — 'roster' is the word
294
293
  // modules/hall-ui/CLAUDE.md uses, but Builders is what a reader scans for.
295
294
  { id: 'roster', label: 'Builders', icon: 'leaderboard', href: '/roster', gate: 'signed' },
296
- // task 1002577: the cross-project builder directory (/scouting graduated
297
- // into the hall). Gated to MATCH its data — /api/bongos/scouting checks
298
- // `project.curate`, whose catalog floor is METIC. This read 'archon' until
299
- // task 1002710: the nav was stricter than the wall, so a Metic could open
300
- // /people by URL but never saw the link. Cosmetic either way —
301
- // requireProjectCuratePage is the wall — but a nav that disagrees with the
302
- // gate teaches the ladder wrong. The module gate hides the tab on
303
- // instances without the platform-identity hub.
304
- { id: 'people', label: 'People', icon: 'people', href: '/people', gate: 'government', module: 'platform-identity' },
295
+ // task 1003444: 'People', the cross-project directory, was deleted (owner
296
+ // call 2026-09-25, ADR 0337 D5). Cross-project discovery is the hub's, and
297
+ // /people redirects to /roster.
305
298
  ] },
306
299
  { group: 'Docs', gate: 'signed', items: [
307
300
  // task 1002710: primer + diagrams were gate:'member' (rank !== xenos) to
@@ -66,7 +66,7 @@
66
66
 
67
67
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
68
68
 
69
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
69
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
70
70
  <script src="/builders/palette.js" defer></script>
71
71
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
72
72
  <!-- The kit, for its ONE renderer: the full-size ship-time visual figure
@@ -3391,15 +3391,8 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
3391
3391
  does not exist, so "Someone helped" rendered full-size on every row. */
3392
3392
  .btn--sm { min-height: 26px; padding: 0 11px; font-size: 12.5px; }
3393
3393
 
3394
- /* people.js:45 — the builder's name cell. The hall's only definition used to
3395
- live in scouting.html's inline <style>, so the same data read bold on
3396
- Scouting and plain on People. It lives here now, and scouting.html itself
3397
- went with task 1003440. */
3398
- .who { font-weight: 600; }
3399
-
3400
- /* people.js:105 — notice() sets body.className='note'. .note lives in
3401
- my-projects.css, which People never loads, so every gated / empty / error
3402
- message on that page rendered unstyled. */
3394
+ /* The notice line: roster.js and blockers.js notice() set body.className='note'
3395
+ for an empty / error message, and neither page's sheet defines it. */
3403
3396
  .note { margin: 0; font-size: 13.5px; color: var(--ink-soft); }
3404
3397
 
3405
3398
  .empty-state { padding: 8px 0; }
@@ -57,7 +57,7 @@
57
57
 
58
58
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
59
59
  time so the chrome exists before the deferred page scripts execute. -->
60
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
60
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
61
61
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
62
62
  <script src="/builders/palette.js" defer></script>
63
63
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so task.js can pull from it. -->
@@ -162,7 +162,7 @@
162
162
 
163
163
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
164
164
  chrome exists before the page script runs. -->
165
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
165
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
166
166
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
167
167
  <script src="/builders/palette.js" defer></script>
168
168
  <!-- shared frontend toolkit (window.OTB) — loaded before watch.js, which pulls from it. -->
@@ -171,7 +171,7 @@
171
171
 
172
172
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
173
173
  time so the chrome exists before the deferred page scripts execute. -->
174
- <script src="/builders/shell.js?v=2026-09-26-swupdate"></script>
174
+ <script src="/builders/shell.js?v=2026-09-26-nopeople"></script>
175
175
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
176
176
  <script src="/builders/palette.js" defer></script>
177
177
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so work.js can pull from it. -->
@@ -2,7 +2,7 @@
2
2
 
3
3
  **The BUILDERS page landed next (task 1003441, goal 1000075)** — the in-project roster, at `/roster`. It is not a redesign but a MOVE: the Roll was a `#leaderboard` HASH VIEW on `index.html`, which is why the Community group read as one real page plus a link into the home page. Four things it settled:
4
4
 
5
- - **The load-bearing part was not the markup.** `shell.js` `VIEWS`, `dom-utils.js` `HALL_VIEWS` and `hall-widgets.js` all declared `leaderboard`; the table, its pager, its sort lenses (`LB_SORT_HEADERS`, `sortedLeaderboardRows`) and the achievement laurels (`ACH_EMOJI`) lived in `hall-render.js`. All of it MOVED to `roster.js` rather than being copied, so Home carries no dead renderer. `roster.html` is the board archetype at people.html’s shape and reuses `people.css` for the identity cell — one definition, both rosters.
5
+ - **The load-bearing part was not the markup.** `shell.js` `VIEWS`, `dom-utils.js` `HALL_VIEWS` and `hall-widgets.js` all declared `leaderboard`; the table, its pager, its sort lenses (`LB_SORT_HEADERS`, `sortedLeaderboardRows`) and the achievement laurels (`ACH_EMOJI`) lived in `hall-render.js`. All of it MOVED to `roster.js` rather than being copied, so Home carries no dead renderer. `roster.html` is the board archetype at people.html’s shape and reuses `people.css` for the identity cell — one definition, both rosters, until task 1003444 deleted `/people` and the sheet became `roster.css`.
6
6
  - **`lbState` and `leaderboardPlace()` STAYED on Home**, shrunk to `{ rows: [] }`. The Standing card still says "#N on the leaderboard", and it needs the same rows; the fetch stays too. Verified live: the card reads `#4 on the leaderboard` with the table gone.
7
7
  - **The hash REDIRECTS, it does not alias.** `#achievements` could fold into Standing because Standing exists on that page; there is no host view for a Roll that left. So `VIEW_REDIRECTS` in `shell.js` sends `#leaderboard` to `/roster` via `location.replace`, guarded to the index — without it `viewFromHash` returns nothing and `route()` silently leaves the reader on Home, a dead link that looks like it worked.
8
8
  - **It is deliberately UNGATED,** and `tests/hall_page_gate_map.mjs` spells that out rather than defaulting. Its one data source, `GET /leaderboard`, is deliberately unauthenticated and mirrors the public status surface; a page must not be gated tighter than the API it fronts, and it was already reachable to a stranger as a view on the ungated index. No visibility predicate is applied and that is correct — privacy suppresses cross-project surfaces only, so a `private` builder still appears on the roster of a project they build on (ADR 0225).
@@ -1,9 +1,9 @@
1
- # The roster and ledger pages — goals, sessions and people (task 1003470; scouting became /people in task 1003440)
1
+ # The roster and ledger pages — goals, sessions and people (task 1003470; scouting became /people in task 1003440; /people deleted in task 1003444)
2
2
 
3
3
  **The ROSTER and LEDGER pages landed next (task 1003470)** — goals, sessions, people and scouting. Goals is the archetype page (`docs/design/mocks/hall/goals/v3.html`) and the page the owner was looking at when he called the re-skin a re-skin, so this pass changed its COMPOSITION rather than its tokens. Five things it settled:
4
4
 
5
5
  - **The goals list is ONE panel.** The filter bar, the count line, the readiness band and the groups sit on one `.scroll` (`.goals-panel`); the bar of twelve controls on the ground over a `--bg-card` panel PER GROUP is gone. Three lenses stay in the open (version, state, sort) and the five rarely turned sit behind the kit's Filters disclosure, **which counts and chips whatever is active so a hidden filter can never narrow the board silently.** `rows|cards` is a VIEW, not a filter: a segmented toggle on the count line writes a hidden `#f-goal-view`, so task 1003136's fork in `renderList` and the `otb.goals.view` pref are unchanged; the pressed side takes `--accent-tint` (the tint the world gives a current thing), **never the accent fill.**
6
6
  - **Three languages on a row, not four.** The ring is the goal's own done-when (satisfied over total, **the arc in INK — the accent lights the pressable and a progress arc is neither**); the facts line is every label a goal carries; the right column is ONE thing — `claim next` as the shell's `.btn-accent` (**the row's only accent**), `what's blocking` as a ghost pill, or a one-line state with a drawn check. The readiness is the family's `.ov-figs` band with the roll line's own `.gr-mark` dots (**classes, not inline styles**), so the band and the rows read as one language.
7
7
  - **The card is the row folded.** The toggle stays because the mock keeps it (a card wall is the better read when scanning for a NAME), but a card inside the panel draws no box — a `--bg-card` tile on a `--bg-card` panel is the card-in-a-card v3 removed — so `.goal-grid` paints the hairline BETWEEN its rows (a 1px row gap over `--rule-soft`, each cell on the panel's ground) and every cell renders the same facts from `goalRenderFacts`.
8
- - **People and scouting are ONE page.** `/scouting` was the legacy door to the same `/api/gds/scouting` rollup, drawn a third way; it now renders `people.html`'s body and `scouting.js` is deleted. **Task 1003440 then deleted the door itself**: `scouting.html` and `scouting.states.json` are gone, the `SCOUTING_PAGE_RE` page gate with them, and `/builders/scouting` now 301s to `/people` (`SCOUTING_LEGACY_RE` in `serve-internal.js`) so an old bookmark still lands on the directory. `tests/hall_roster_world.mjs` pins both halves — the files are absent, and the redirect exists with no dead gate behind it. On the row the name is the shell's `.lb-name` to the builder's **GitHub** page — the one door every listed builder has, since the directory is cross-project and no local profile id exists. The gate copy is written from `OTB.rankLabel('metic')`; it used to say "Archon-only", wrong since ADR 0210.
8
+ - **People and scouting are ONE page.** `/scouting` was the legacy door to the same `/api/gds/scouting` rollup, drawn a third way; it now renders `people.html`'s body and `scouting.js` is deleted. **Task 1003440 then deleted the door itself**: `scouting.html` and `scouting.states.json` are gone, the `SCOUTING_PAGE_RE` page gate with them, and `/builders/scouting` now 301s to `/people` (`SCOUTING_LEGACY_RE` in `serve-internal.js`) so an old bookmark still lands on the directory. `tests/hall_roster_world.mjs` pins both halves — the files are absent, and the redirect exists with no dead gate behind it. On the row the name is the shell's `.lb-name` to the builder's **GitHub** page — the one door every listed builder has, since the directory is cross-project and no local profile id exists. The gate copy is written from `OTB.rankLabel('metic')`; it used to say "Archon-only", wrong since ADR 0210. **Task 1003444 then deleted `/people` itself** (owner call, 2026-09-25 — [ADR 0337](../../../docs/adr/0337-the-hub-account-is-the-person-a-hall-account-is-their-seat-in-one-project.md) D5): cross-project discovery is the hub's, so `people.html`, `people.js`, `people.states.json` and the `scouting.json` harness fixture are gone, the identity cell `/roster` shared moved from `people.css` to `roster.css`, and the `requireProjectCuratePage` page gate (with its `alsoAdmits` door) went with the page. `/builders/people` and `/builders/scouting` now 302 to `/roster` (`RETIRED_DIRECTORY_RE`); GET `/scouting`'s own route gate is unchanged. Cross-project search and the recruiter name-only panel are absent until the hub community page (task 1003363) ships.
9
9
  - **The session ledger's nowrap + wrapper pair was a live bug.** `sessions.css` forced `white-space: nowrap` on every cell, `.ledger-table-wrap` existed only to give that a scrollport, and the shell's sticky `th` then stuck to the WRAPPER — the column heads rendered over the first row on desktop. Both are gone; the shell's card strip handles a phone as on every other ledger. **Every id on a row is a door** (the session id was painted in `--info` — a link to nowhere); the row shows what the session EARNED; the totals ride the shell's top strip (`.ov-summary`) with **six fixed columns so the sixth tile is never stranded on its own row**. The hand-rolled server-side pager is untouched (the sanctioned exception below).
@@ -124,8 +124,8 @@ function isAccountActive(account) {
124
124
  // The rollup axis: visible AND not hidden (task 1002967 — ADR 0171 D2 extended)
125
125
  // -------------------------------------------------------------------------
126
126
 
127
- // The predicate the two ROLLUP readers join — listScoutingRollup (/people,
128
- // /scouting) and getPublicProfileExtras (the platform-identity.hub port behind
127
+ // The predicate the two ROLLUP readers join — listScoutingRollup
128
+ // (/scouting) and getPublicProfileExtras (the platform-identity.hub port behind
129
129
  // core GET /builders/:id/profile). COMPOSED from accountVisibleSql, never
130
130
  // restated, so changing what "visible" means moves this with it.
131
131
  function rollupVisibleSql(alias) {
@@ -185,7 +185,7 @@ function recruiterReachSql(alias) {
185
185
 
186
186
  // scoutingListableSql — THE predicate the recruiting directory joins: the rollup
187
187
  // axis AND the reach axis (ADR 0210, task 1002290). listScoutingRollup is the
188
- // one reader; /scouting and the hall's /people are its two surfaces.
188
+ // one reader; GET /scouting is its surface (the hall's /people went, task 1003444).
189
189
  //
190
190
  // WHY REACH BELONGS HERE AND NOT IN rollupVisibleSql. The two axes answer
191
191
  // different questions and only one surface asks both. `hide_stats` suppresses
@@ -701,8 +701,8 @@ async function upsertActivity({ clientId, githubId, credits = 0, tasksShipped =
701
701
  //
702
702
  // Consent by construction (ADR 0171 D2/D3, extended by tasks 1002967 + 1002290):
703
703
  // only builders whose account passes scoutingListableSql — active, publicly
704
- // visible, not hidden, AND not opted out of recruiting — appear. /people and
705
- // /scouting are live cross-project surfaces, so the predicate lives IN the query,
704
+ // visible, not hidden, AND not opted out of recruiting — appear. /scouting is a
705
+ // live cross-project surface, so the predicate lives IN the query,
706
706
  // not in any caller's memory, and it is the SHARED one so this list can never
707
707
  // disagree with /profiles/:handle about who is visible. Provisional, private,
708
708
  // hidden and opted-out builders drop out entirely; the projection stays an
@@ -14,7 +14,7 @@
14
14
  // account_visibility + recruiter_discoverable (task
15
15
  // 1002966, privacy spec D1). hide_stats takes effect
16
16
  // immediately on every public surface (profile
17
- // cross_project, /people, /scouting): enforcement
17
+ // cross_project, /scouting): enforcement
18
18
  // lives in the module's read functions (D2) and the
19
19
  // hub profile response is no-store (D5), so there is
20
20
  // no cache to outwait. The other two are STORED here
@@ -174,9 +174,10 @@ function registerSeams() {
174
174
  // which a database error must never be allowed to say.
175
175
  hiddenGithubIds: (githubIds) => pi.hiddenGithubIds(githubIds, { pool }),
176
176
  // task 1002290 (ADR 0210): "does this hub account own a project?", the
177
- // second audience the /people page gate admits beside `project.curate`.
178
- // The ownership fact lives in this module, so the answer does too; core
179
- // asks through the port and treats an absent one as a denial.
177
+ // second audience a page gate's `alsoAdmits` door admits — today the /deploy
178
+ // shell (requireCorePinPage, ADR 0339); /people, its first user, is deleted
179
+ // (task 1003444). The ownership fact lives in this module, so the answer does
180
+ // too; core asks through the port and treats an absent one as a denial.
180
181
  isProjectOwner: (githubId) => scoutingAuthz.hasOwnerMembership(githubId, { pool }),
181
182
  // task 1002347 (BV1.R28, ADR 0251): the names behind `invites.seeking` —
182
183
  // the creation wizard's "who is worth inviting" list. Consent-filtered by
@@ -1,6 +1,6 @@
1
1
  // modules/platform-identity/scouting-authz.js — WHO may read the cross-project
2
- // recruiting directory (GET /scouting; the hall's /people page renders the same
3
- // data). ADR 0210, task 1002290 — goal 1000045 C5: "project owners (not only
2
+ // recruiting directory (GET /scouting; the hall's /people page that rendered it
3
+ // was deleted in task 1003444). ADR 0210, task 1002290 — goal 1000045 C5: "project owners (not only
4
4
  // Archons) browse builder profiles to recruit".
5
5
  //
6
6
  // TWO DOORS, DELIBERATELY DIFFERENT KINDS — the modules/lifecycle/goal-authz.js