@bongos/core 1.20.17 → 1.20.18
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 +16 -16
- package/docs/adr/0213-platform-terms-acceptance-is-the-hubs-own-witness.md +2 -0
- package/docs/copy-inventory.md +5 -6
- package/docs/copy-registry.json +8 -17
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-readings.json +7 -7
- package/modules/public-landing/public/terms.html +3 -3
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/module-api.js +1 -1
- package/tests/terms_acceptance.mjs +114 -8
package/.bongos-core.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.20.
|
|
6
|
-
"core_contract": "1.20.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.20.18",
|
|
6
|
+
"core_contract": "1.20.18",
|
|
7
|
+
"source_commit": "e1841ec9f7044de186bb75988136b6dfb0835ef7",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-30T13:
|
|
9
|
+
"built_at": "2026-09-30T13:46:50.940Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 556,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 3210,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "34fda46e51438cef84700eb352c0f4dc3a8552cd8e8fc962864f4f500e09047d",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -1537,7 +1537,7 @@
|
|
|
1537
1537
|
{
|
|
1538
1538
|
"path": "docs/adr/0213-platform-terms-acceptance-is-the-hubs-own-witness.md",
|
|
1539
1539
|
"mode": "0000644",
|
|
1540
|
-
"sha256": "
|
|
1540
|
+
"sha256": "2e00d10ae548548bc8708058b0beb08fc0631aa29f27f6905ef630fdf4c6099b"
|
|
1541
1541
|
},
|
|
1542
1542
|
{
|
|
1543
1543
|
"path": "docs/adr/0214-canonical-profile-url-one-resolver-dark-until-the-page-exists.md",
|
|
@@ -2267,12 +2267,12 @@
|
|
|
2267
2267
|
{
|
|
2268
2268
|
"path": "docs/copy-inventory.md",
|
|
2269
2269
|
"mode": "0000644",
|
|
2270
|
-
"sha256": "
|
|
2270
|
+
"sha256": "08ef6d32a1c5cfea14e7ddd54a4e7ab2e34818199a45e0422a4fce31b72567a7"
|
|
2271
2271
|
},
|
|
2272
2272
|
{
|
|
2273
2273
|
"path": "docs/copy-registry.json",
|
|
2274
2274
|
"mode": "0000644",
|
|
2275
|
-
"sha256": "
|
|
2275
|
+
"sha256": "a405d02a6308a53e9322437f21daf86cb7e7f0d6d8b15a25639b7fdbcb7c2fd1"
|
|
2276
2276
|
},
|
|
2277
2277
|
{
|
|
2278
2278
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2772,7 +2772,7 @@
|
|
|
2772
2772
|
{
|
|
2773
2773
|
"path": "docs/module-api-changelog.md",
|
|
2774
2774
|
"mode": "0000644",
|
|
2775
|
-
"sha256": "
|
|
2775
|
+
"sha256": "99307d7bab261c46f7e80d768b014352d9f3c47ec2c72088acfac7bc700dd06f"
|
|
2776
2776
|
},
|
|
2777
2777
|
{
|
|
2778
2778
|
"path": "docs/modules-contract.md",
|
|
@@ -2862,7 +2862,7 @@
|
|
|
2862
2862
|
{
|
|
2863
2863
|
"path": "docs/page-readings.json",
|
|
2864
2864
|
"mode": "0000644",
|
|
2865
|
-
"sha256": "
|
|
2865
|
+
"sha256": "6ba44419e75dcb245e386e077eba647e744c56861b8b81c9002bbe7528369f0c"
|
|
2866
2866
|
},
|
|
2867
2867
|
{
|
|
2868
2868
|
"path": "docs/project-context.template.md",
|
|
@@ -8032,7 +8032,7 @@
|
|
|
8032
8032
|
{
|
|
8033
8033
|
"path": "modules/public-landing/public/terms.html",
|
|
8034
8034
|
"mode": "0000644",
|
|
8035
|
-
"sha256": "
|
|
8035
|
+
"sha256": "39aae17cd14c496533f9a212f37378571d9d621c078353e41900a02c5355df5f"
|
|
8036
8036
|
},
|
|
8037
8037
|
{
|
|
8038
8038
|
"path": "modules/render-deploy/deploys.js",
|
|
@@ -8862,12 +8862,12 @@
|
|
|
8862
8862
|
{
|
|
8863
8863
|
"path": "package-lock.json",
|
|
8864
8864
|
"mode": "0000644",
|
|
8865
|
-
"sha256": "
|
|
8865
|
+
"sha256": "35d3b7a5f69caee9c6a98b7c34c02daec4289cd0548637d05ff41fd23d1926c4"
|
|
8866
8866
|
},
|
|
8867
8867
|
{
|
|
8868
8868
|
"path": "package.json",
|
|
8869
8869
|
"mode": "0000644",
|
|
8870
|
-
"sha256": "
|
|
8870
|
+
"sha256": "9807202c95ba59b5f8104eb0c6701241d989800e67fdddf8252bc569b9a74c96"
|
|
8871
8871
|
},
|
|
8872
8872
|
{
|
|
8873
8873
|
"path": "public-docs/index.html",
|
|
@@ -8887,7 +8887,7 @@
|
|
|
8887
8887
|
{
|
|
8888
8888
|
"path": "release-notes.json",
|
|
8889
8889
|
"mode": "0000644",
|
|
8890
|
-
"sha256": "
|
|
8890
|
+
"sha256": "19b0f5588a02e7517cc25668a59df836f8ee1a183e1f1ec4a2b63d79214b3808"
|
|
8891
8891
|
},
|
|
8892
8892
|
{
|
|
8893
8893
|
"path": "scripts/bongos-mcp.js",
|
|
@@ -11002,7 +11002,7 @@
|
|
|
11002
11002
|
{
|
|
11003
11003
|
"path": "src/module-api.js",
|
|
11004
11004
|
"mode": "0000644",
|
|
11005
|
-
"sha256": "
|
|
11005
|
+
"sha256": "3f49c56de113748d04529b5028e1ac2fca037cf00c1d6be6e531346dcfbea552"
|
|
11006
11006
|
},
|
|
11007
11007
|
{
|
|
11008
11008
|
"path": "src/module-loader/catalog.js",
|
|
@@ -15757,7 +15757,7 @@
|
|
|
15757
15757
|
{
|
|
15758
15758
|
"path": "tests/terms_acceptance.mjs",
|
|
15759
15759
|
"mode": "0000644",
|
|
15760
|
-
"sha256": "
|
|
15760
|
+
"sha256": "80ea17a764ba05a05af0967e9951370b814c20c3518a37f1c3ca1a9ca0d044cf"
|
|
15761
15761
|
},
|
|
15762
15762
|
{
|
|
15763
15763
|
"path": "tests/terms_grandfather_db.mjs",
|
|
@@ -29,6 +29,8 @@ This is deliberately the ADR 0205 D3 property, reused. An acceptance record a ca
|
|
|
29
29
|
|
|
30
30
|
> **Amended 2026-09-25 ([task 1003353](https://cloudbongos.com/builders#/task/1003353); [blocker 1000124](https://cloudbongos.com/builders#/blocker/1000124)) — what "the hub's own sign-in" means.** `GET /sso/authorize` is reached when a builder uses their platform account to sign in to a **project**; the only builder of that URL is a child instance's `idpAuthorizeUrl`. Signing in to the hub itself creates a hub session and never touches `platform_identity_accounts`, so it records no acceptance. `/terms` said "signed in here"; it now names a project sign-in. The owner chose to also capture the hub's own sign-in ([task 1003361](https://cloudbongos.com/builders#/task/1003361)), which will make this a second capture point rather than a wording fix. Two smaller corrections to the text above: the device poll does not go through `ensureAccount`, it is a non-activating `upsertAccount`, and so is `PATCH /me/handle`; `ensureAccount` is the federated membership check-in alone. The outcome was always the same (neither writes an acceptance), and both paths are now executed in `tests/terms_acceptance.mjs` rather than asserted as text.
|
|
31
31
|
|
|
32
|
+
> **Amended 2026-09-30 ([task 1004265](https://cloudbongos.com/builders#/task/1004265)) — a project sign-in *in the browser*.** The CLI's project sign-in (`POST /sso/device/poll`) also uses the platform account, and it stays **non-activating on purpose**. The person approves it on GitHub's device page, never on a hub page, so these terms are never in front of them — and the same branch that stamps the acceptance also flips `profile_state` to active, which ADR 0171 D3 reserves for the one path "where a human is demonstrably at the hub" — and D3 names the device poll as `provisional` in so many words. Stamping it would record consent nobody was shown and re-decide D3 by implementation convenience. `/terms` therefore names a project sign-in **in your browser**, and says that a command-line sign-in records nothing and why, so a CLI-only builder is not left guessing why they are unpublished. `tests/terms_acceptance.mjs` §3 drives the real device-poll route (no acceptance, still provisional, the non-activating literal, a forged body refused before any write) and a later browser sign-in stamping that same account. The "next hub sign-in" wording under D4 is left for task 1003361, which makes it true.
|
|
33
|
+
|
|
32
34
|
### D2 — Written once. The first acceptance is the one that stands
|
|
33
35
|
|
|
34
36
|
The conflict branch writes `COALESCE(platform_identity_accounts.terms_accepted_at, now())`. Signing in again re-reads the terms but does not restamp them, so the column keeps meaning *when consent was given* rather than *when this account was last seen*. `terms_version` is COALESCE'd the same way and always written in the same statement, so the pair cannot diverge.
|
package/docs/copy-inventory.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
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
|
+
**2188 strings** across 3 surfaces · 1888 distinct pieces of copy · 2188 certain, 0 heuristic · 207 shown in more than one place.
|
|
8
8
|
|
|
9
9
|
## Surfaces
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|---|---|---|---|
|
|
13
13
|
| `builders-hall` | `modules/hall-ui/public` | 109 | 1617 |
|
|
14
14
|
| `status-dashboard` | `modules/status-ui/public` | 4 | 100 |
|
|
15
|
-
| `landing` | `modules/public-landing/public` | 6 |
|
|
15
|
+
| `landing` | `modules/public-landing/public` | 6 | 471 |
|
|
16
16
|
|
|
17
17
|
## Confidence, and why it is on every row
|
|
18
18
|
|
|
@@ -1805,7 +1805,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1805
1805
|
| `7667eb552781` | certain | {…}: {…}% ({…}/{…} checks) | `modules/status-ui/public/status.js:468` |
|
|
1806
1806
|
| `6d0d64f10bd9` | certain | ‹ earlier page | `modules/status-ui/public/index.html:321` |
|
|
1807
1807
|
|
|
1808
|
-
## `landing` —
|
|
1808
|
+
## `landing` — 471 strings
|
|
1809
1809
|
|
|
1810
1810
|
| id | conf | text | where |
|
|
1811
1811
|
|---|---|---|---|
|
|
@@ -1940,7 +1940,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1940
1940
|
| `485c565b5745` | certain | How people join | `modules/public-landing/public/projects.html:910` |
|
|
1941
1941
|
| `4b542b000afa` | certain | How this project is drawn: on the sky, in your list, at the top of this page and on its card. A planet is a | `modules/public-landing/public/projects.html:1030` |
|
|
1942
1942
|
| `9f31eaed8252` | certain | If you grant repository access while creating a project, that permission is used to create or adopt your repos | `modules/public-landing/public/privacy.html:55` |
|
|
1943
|
-
| `
|
|
1943
|
+
| `d37e2fbde8c6` | certain | If your account already existed when this version took effect, the platform accepted it on your behalf, rather | `modules/public-landing/public/terms.html:71` |
|
|
1944
1944
|
| `607551ae732b` | certain | Invite a builder | `modules/public-landing/public/projects.html:1003` |
|
|
1945
1945
|
| `20786b02f47a` | certain | Invite builders | `modules/public-landing/public/projects.html:1492` |
|
|
1946
1946
|
| `a1256030d879` | certain | Invite only | `modules/public-landing/public/projects.html:914` |
|
|
@@ -1979,7 +1979,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1979
1979
|
| `837fdaa0936a` | certain | Nothing matches that. | `modules/public-landing/public/projects.html:707` |
|
|
1980
1980
|
| `1bc11853e893` | certain | On the map | `modules/public-landing/public/projects.html:929` |
|
|
1981
1981
|
| `b4ac8f44710c` | certain | On the public map | `modules/public-landing/public/projects.html:851` |
|
|
1982
|
-
| `
|
|
1982
|
+
| `1fdda2903cf9` | certain | Once you have signed in to a project in your browser with your platform account and accepted these terms, your | `modules/public-landing/public/terms.html:68` |
|
|
1983
1983
|
| `8329bb1a3693` | certain | One tap files the request and the platform starts standing your project up — server, database, address. Here's | `modules/public-landing/public/projects.html:1462` |
|
|
1984
1984
|
| `86cde1930d84` | certain | Only mine | `modules/public-landing/public/projects.html:477` |
|
|
1985
1985
|
| `f82fe1982ab3` | certain | Open an issue on the repository | `modules/public-landing/public/contact.html:52` |
|
|
@@ -2092,7 +2092,6 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
2092
2092
|
| `fb416bf1a26b` | certain | The handle names your project on the platform — and its address comes with it. Once it stands up, a few GitHub | `modules/public-landing/public/projects.html:1355` |
|
|
2093
2093
|
| `a954f0dce9a3` | certain | The platform | `modules/public-landing/public/contact.html:65` |
|
|
2094
2094
|
| `4fd8f5746cc5` | certain | The platform is run as a non-profit, capture-resistant commons. | `modules/public-landing/public/terms.html:50` |
|
|
2095
|
-
| `dede132846fe` | certain | The platform stores the date you accepted these terms, and which version, on your account. It is written when | `modules/public-landing/public/terms.html:70` |
|
|
2096
2095
|
| `20fcebaa85c4` | certain | The project hub needs JavaScript — the map, your projects, and starting a new one all live here. You can read | `modules/public-landing/public/projects.html:530` |
|
|
2097
2096
|
| `4a740b5afe73` | certain | The project map | `modules/public-landing/public/projects.html:540` |
|
|
2098
2097
|
| `345fec12e5d8` | certain | The repository | `modules/public-landing/public/contact.html:50` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"generator": "scripts/gds/copy-inventory.js",
|
|
4
4
|
"goal": 1000074,
|
|
5
5
|
"counts": {
|
|
6
|
-
"strings":
|
|
7
|
-
"unique_ids":
|
|
8
|
-
"certain":
|
|
6
|
+
"strings": 2188,
|
|
7
|
+
"unique_ids": 1888,
|
|
8
|
+
"certain": 2188,
|
|
9
9
|
"heuristic": 0,
|
|
10
10
|
"duplicate_ids": 207
|
|
11
11
|
},
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"landing": {
|
|
24
24
|
"at": "modules/public-landing/public",
|
|
25
25
|
"files": 6,
|
|
26
|
-
"strings":
|
|
26
|
+
"strings": 471
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"blind_spots": [
|
|
@@ -17936,9 +17936,9 @@
|
|
|
17936
17936
|
"confidence": "certain"
|
|
17937
17937
|
},
|
|
17938
17938
|
{
|
|
17939
|
-
"id": "
|
|
17939
|
+
"id": "d37e2fbde8c6",
|
|
17940
17940
|
"surface": "landing",
|
|
17941
|
-
"text": "If your account already existed when this version took effect, the platform accepted it on your behalf, rather than waiting for you to sign in, and dated it the day that was done. The record marks that acceptance as grandfathered, so it is never mistaken for one you gave, and your own acceptance replaces it the next time you sign in to a project.",
|
|
17941
|
+
"text": "If your account already existed when this version took effect, the platform accepted it on your behalf, rather than waiting for you to sign in, and dated it the day that was done. The record marks that acceptance as grandfathered, so it is never mistaken for one you gave, and your own acceptance replaces it the next time you sign in to a project in your browser.",
|
|
17942
17942
|
"file": "modules/public-landing/public/terms.html",
|
|
17943
17943
|
"line": 71,
|
|
17944
17944
|
"origin": "html-text",
|
|
@@ -18287,9 +18287,9 @@
|
|
|
18287
18287
|
"confidence": "certain"
|
|
18288
18288
|
},
|
|
18289
18289
|
{
|
|
18290
|
-
"id": "
|
|
18290
|
+
"id": "1fdda2903cf9",
|
|
18291
18291
|
"surface": "landing",
|
|
18292
|
-
"text": "Once you have signed in to a project with your platform account and accepted these terms, your profile and that record are public by default: at your handle’s page, in the people directory, to project owners looking for people to work with, and to search engines. An account that has never signed in to a project that way stays provisional and is published nowhere.",
|
|
18292
|
+
"text": "Once you have signed in to a project in your browser with your platform account and accepted these terms, your profile and that record are public by default: at your handle’s page, in the people directory, to project owners looking for people to work with, and to search engines. An account that has never signed in to a project that way stays provisional and is published nowhere.",
|
|
18293
18293
|
"file": "modules/public-landing/public/terms.html",
|
|
18294
18294
|
"line": 68,
|
|
18295
18295
|
"origin": "html-text",
|
|
@@ -19303,15 +19303,6 @@
|
|
|
19303
19303
|
"origin": "html-text",
|
|
19304
19304
|
"confidence": "certain"
|
|
19305
19305
|
},
|
|
19306
|
-
{
|
|
19307
|
-
"id": "dede132846fe",
|
|
19308
|
-
"surface": "landing",
|
|
19309
|
-
"text": "The platform stores the date you accepted these terms, and which version, on your account. It is written when you sign in to a project with your platform account, and only once — signing in again does not change the date you accepted. This is version",
|
|
19310
|
-
"file": "modules/public-landing/public/terms.html",
|
|
19311
|
-
"line": 70,
|
|
19312
|
-
"origin": "html-text",
|
|
19313
|
-
"confidence": "certain"
|
|
19314
|
-
},
|
|
19315
19306
|
{
|
|
19316
19307
|
"id": "20fcebaa85c4",
|
|
19317
19308
|
"surface": "landing",
|
|
@@ -2691,5 +2691,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2691
2691
|
landed since 1.20.15 with no explicit bump. run 36717488992. (task 1002620)
|
|
2692
2692
|
1.20.17 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2693
2693
|
landed since 1.20.16 with no explicit bump. run 36722139698. (task 1002620)
|
|
2694
|
+
1.20.18 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2695
|
+
landed since 1.20.17 with no explicit bump. run 36724081934. (task 1002620)
|
|
2694
2696
|
---------------------------------------------------------------------------
|
|
2695
2697
|
```
|
package/docs/page-readings.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"adr": "0341 D3",
|
|
6
6
|
"reread": "node scripts/gds/page-reader.js --stale",
|
|
7
7
|
"how": ["Generated by node scripts/gds/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":39,"lines":3791,"placed":
|
|
8
|
+
"counts": {"pages":39,"lines":3791,"placed":1277,"shared":254,"unplaced":2260,"omitted_data":2054},
|
|
9
9
|
"pages": [
|
|
10
10
|
{
|
|
11
11
|
"id": "builders:atlas",
|
|
@@ -4132,9 +4132,9 @@
|
|
|
4132
4132
|
"surface": "landing",
|
|
4133
4133
|
"title": "{{productName}} — Terms",
|
|
4134
4134
|
"states_read": ["default"],
|
|
4135
|
-
"files_hash": "
|
|
4136
|
-
"reading_hash": "
|
|
4137
|
-
"counts": {"lines":45,"placed":
|
|
4135
|
+
"files_hash": "5f1171d0ce6fb7d3",
|
|
4136
|
+
"reading_hash": "007bea800099720b",
|
|
4137
|
+
"counts": {"lines":45,"placed":28,"shared":9,"unplaced":8},
|
|
4138
4138
|
"omitted": {"data":1},
|
|
4139
4139
|
"notes": [],
|
|
4140
4140
|
"lines": [
|
|
@@ -4158,13 +4158,13 @@
|
|
|
4158
4158
|
{"key":"L0018","section":"Your work across projects","text":"These numbers describe; they do not govern.","placement":"placed","file":"modules/public-landing/public/terms.html","line":67,"string_id":"02e596cc4569"},
|
|
4159
4159
|
{"key":"L0019","section":"Your work across projects","text":"Your cross-project record is descriptive analytics and never authority. What you may do inside any project is decided by that project alone, from its own records, at the moment you ask. A large record grants nothing and a hidden one takes nothing away; no project is required to read it, and {…} may treat it as permission. A rank shown here is that project’s own standing for you, as that project reported it — the platform holds no rank of its own.","placement":"unplaced"},
|
|
4160
4160
|
{"key":"L0020","section":"Your work across projects","text":"What is public.","placement":"placed","file":"modules/public-landing/public/terms.html","line":68,"string_id":"9b3312899fb1"},
|
|
4161
|
-
{"key":"L0021","section":"Your work across projects","text":"Once you have signed in to a project with your platform account and accepted these terms, your profile and that record are public by default: at your handle’s page, in the people directory, to project owners looking for people to work with, and to search engines. An account that has never signed in to a project that way stays provisional and is published nowhere.","placement":"placed","file":"modules/public-landing/public/terms.html","line":68,"string_id":"
|
|
4161
|
+
{"key":"L0021","section":"Your work across projects","text":"Once you have signed in to a project in your browser with your platform account and accepted these terms, your profile and that record are public by default: at your handle’s page, in the people directory, to project owners looking for people to work with, and to search engines. An account that has never signed in to a project that way stays provisional and is published nowhere.","placement":"placed","file":"modules/public-landing/public/terms.html","line":68,"string_id":"1fdda2903cf9"},
|
|
4162
4162
|
{"key":"L0022","section":"Your work across projects","text":"What you control.","placement":"placed","file":"modules/public-landing/public/terms.html","line":69,"string_id":"6130dcb60532"},
|
|
4163
4163
|
{"key":"L0023","section":"Your work across projects","text":"From your settings you can hide your statistics, drop out of the recruiting directory, or make your account private. Each takes effect immediately, everywhere, including on a page someone already has open. Hiding removes the platform’s combined view; it does not retract the per-project numbers each project publishes itself, so a determined reader could still add them up the hard way.","placement":"placed","file":"modules/public-landing/public/terms.html","line":69,"string_id":"0808df6e434c"},
|
|
4164
4164
|
{"key":"L0024","section":"Your work across projects","text":"Your acceptance is recorded.","placement":"placed","file":"modules/public-landing/public/terms.html","line":70,"string_id":"0f06f7e72ea7"},
|
|
4165
|
-
{"key":"L0025","section":"Your work across projects","text":"The platform stores the date you accepted these terms, and which version, on your account. It is written when you sign in to a project with your platform account, and only once — signing in again does not change the date you accepted. This is version","placement":"
|
|
4165
|
+
{"key":"L0025","section":"Your work across projects","text":"The platform stores the date you accepted these terms, and which version, on your account. It is written when you sign in to a project in your browser with your platform account, and only once — signing in again does not change the date you accepted. Signing in from the command line does not record it: you approve that sign-in on GitHub’s page, where these terms are not shown, so an account that has only signed in that way stays unpublished until you sign in to a project in your browser once. This is version","placement":"unplaced"},
|
|
4166
4166
|
{"key":"L0026","section":"Your work across projects","text":"Accounts from before these terms.","placement":"placed","file":"modules/public-landing/public/terms.html","line":71,"string_id":"9b02ec8a2e21"},
|
|
4167
|
-
{"key":"L0027","section":"Your work across projects","text":"If your account already existed when this version took effect, the platform accepted it on your behalf, rather than waiting for you to sign in, and dated it the day that was done. The record marks that acceptance as grandfathered, so it is never mistaken for one you gave, and your own acceptance replaces it the next time you sign in to a project.","placement":"placed","file":"modules/public-landing/public/terms.html","line":71,"string_id":"
|
|
4167
|
+
{"key":"L0027","section":"Your work across projects","text":"If your account already existed when this version took effect, the platform accepted it on your behalf, rather than waiting for you to sign in, and dated it the day that was done. The record marks that acceptance as grandfathered, so it is never mistaken for one you gave, and your own acceptance replaces it the next time you sign in to a project in your browser.","placement":"placed","file":"modules/public-landing/public/terms.html","line":71,"string_id":"d37e2fbde8c6"},
|
|
4168
4168
|
{"key":"L0028","section":"Fair use","text":"Fair use","placement":"placed","file":"modules/public-landing/public/terms.html","line":73,"string_id":"2585087f4873"},
|
|
4169
4169
|
{"key":"L0029","section":"Fair use","text":"Don't use {{productName}} to break the law, to attack this site or other people's projects, to mine, spam or otherwise abuse hosted resources, or to harass other builders. The owner may deactivate a builder or take a project offline for breaking these, and may set further house rules inside the hall.","placement":"placed","file":"modules/public-landing/public/terms.html","line":74,"string_id":"8d812912c392"},
|
|
4170
4170
|
{"key":"L0030","section":"Liability","text":"Liability","placement":"unplaced"},
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
<h2>Your work across projects</h2>
|
|
66
66
|
<p>Each {{productName}} project you build in reports a summary of your work there to the platform: the {{currency}} you earned, the works you shipped, your karma, the rank that project gave you, the roles you worked in, and when you were last active. The platform adds these up across every project into one cross-project record. Projects report this themselves — the platform does not read their databases.</p>
|
|
67
67
|
<p><b>These numbers describe; they do not govern.</b> Your cross-project record is descriptive analytics and never authority. What you may do inside any project is decided by that project alone, from its own records, at the moment you ask. A large record grants nothing and a hidden one takes nothing away; no project is required to read it, and none may treat it as permission. A rank shown here is that project’s own standing for you, as that project reported it — the platform holds no rank of its own.</p>
|
|
68
|
-
<p><b>What is public.</b> Once you have signed in to a project with your platform account and accepted these terms, your profile and that record are public by default: at your handle’s page, in the people directory, to project owners looking for people to work with, and to search engines. An account that has never signed in to a project that way stays provisional and is published nowhere.</p>
|
|
68
|
+
<p><b>What is public.</b> Once you have signed in to a project in your browser with your platform account and accepted these terms, your profile and that record are public by default: at your handle’s page, in the people directory, to project owners looking for people to work with, and to search engines. An account that has never signed in to a project that way stays provisional and is published nowhere.</p>
|
|
69
69
|
<p><b>What you control.</b> From your settings you can hide your statistics, drop out of the recruiting directory, or make your account private. Each takes effect immediately, everywhere, including on a page someone already has open. Hiding removes the platform’s combined view; it does not retract the per-project numbers each project publishes itself, so a determined reader could still add them up the hard way.</p>
|
|
70
|
-
<p><b>Your acceptance is recorded.</b> The platform stores the date you accepted these terms, and which version, on your account. It is written when you sign in to a project with your platform account, and only once — signing in again does not change the date you accepted. This is version <b>2026-08-29</b>.</p>
|
|
71
|
-
<p><b>Accounts from before these terms.</b> If your account already existed when this version took effect, the platform accepted it on your behalf, rather than waiting for you to sign in, and dated it the day that was done. The record marks that acceptance as grandfathered, so it is never mistaken for one you gave, and your own acceptance replaces it the next time you sign in to a project.</p>
|
|
70
|
+
<p><b>Your acceptance is recorded.</b> The platform stores the date you accepted these terms, and which version, on your account. It is written when you sign in to a project in your browser with your platform account, and only once — signing in again does not change the date you accepted. Signing in from the command line does not record it: you approve that sign-in on GitHub’s page, where these terms are not shown, so an account that has only signed in that way stays unpublished until you sign in to a project in your browser once. This is version <b>2026-08-29</b>.</p>
|
|
71
|
+
<p><b>Accounts from before these terms.</b> If your account already existed when this version took effect, the platform accepted it on your behalf, rather than waiting for you to sign in, and dated it the day that was done. The record marks that acceptance as grandfathered, so it is never mistaken for one you gave, and your own acceptance replaces it the next time you sign in to a project in your browser.</p>
|
|
72
72
|
<!--apex-only:end-->
|
|
73
73
|
<h2>Fair use</h2>
|
|
74
74
|
<p>Don't use {{productName}} to break the law, to attack this site or other people's projects, to mine, spam or otherwise abuse hosted resources, or to harass other builders. The owner may deactivate a builder or take a project offline for breaking these, and may set further house rules inside the hall.</p>
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.18",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.20.
|
|
9
|
+
"version": "1.20.18",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.18",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/release-notes.json
CHANGED
|
@@ -8158,5 +8158,11 @@
|
|
|
8158
8158
|
"id": "1003540",
|
|
8159
8159
|
"text": "Guessing someone's private profile name on the recruiting page is now speed-limited, so it can't be used to discover who is open to recruiting."
|
|
8160
8160
|
}
|
|
8161
|
+
],
|
|
8162
|
+
"1.20.18": [
|
|
8163
|
+
{
|
|
8164
|
+
"id": "1004265",
|
|
8165
|
+
"text": "The terms page now says your agreement is recorded when you sign in to a project in your browser, and explains why a command-line-only sign-in doesn't publish your profile."
|
|
8166
|
+
}
|
|
8161
8167
|
]
|
|
8162
8168
|
}
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.20.
|
|
78
|
+
const CORE_VERSION = '1.20.18'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
|
@@ -118,20 +118,32 @@ t('the acceptance the page promises is the one the code actually keeps', () => {
|
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
// The capture point is GET /sso/authorize — reached when a builder uses their
|
|
121
|
-
// platform account to sign in to a PROJECT. Signing in to the hub
|
|
122
|
-
// nothing (blocker 1000124, task 1003353), so the page must not say
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
|
|
121
|
+
// platform account to sign in to a PROJECT, IN A BROWSER. Signing in to the hub
|
|
122
|
+
// itself stamps nothing (blocker 1000124, task 1003353), so the page must not say
|
|
123
|
+
// "here"; and the CLI's project sign-in (the device poll) stamps nothing either
|
|
124
|
+
// (task 1004265, executed in §3), so the page must say "in your browser" and tell a
|
|
125
|
+
// command-line builder why. Task 1003361 adds the hub's own sign-in as a second
|
|
126
|
+
// capture point; when it lands, this wording and §3 below change together.
|
|
127
|
+
t('the page names the sign-in the code actually watches — a project sign-in in the browser, not "here" (blocker 1000124)', () => {
|
|
126
128
|
const section = termsHtml.slice(termsHtml.indexOf('Your work across projects'), termsHtml.indexOf('Fair use'));
|
|
127
129
|
assert.doesNotMatch(section, /sign(?:ed|ing)? in here/i,
|
|
128
130
|
'the page promises that signing in to this site records acceptance — the code never stamps that sign-in');
|
|
129
|
-
assert.match(section, /Once you have signed in to a project with your platform account and accepted these terms/,
|
|
131
|
+
assert.match(section, /Once you have signed in to a project in your browser with your platform account and accepted these terms/,
|
|
130
132
|
'what makes a profile public must name the moment the code captures');
|
|
131
133
|
assert.match(section, /never signed in to a project that way stays provisional/,
|
|
132
134
|
'and the provisional case must be the same moment, negated');
|
|
133
|
-
assert.match(section, /written when you sign in to a project with your platform account, and only once/,
|
|
135
|
+
assert.match(section, /written when you sign in to a project in your browser with your platform account, and only once/,
|
|
134
136
|
'the acceptance paragraph must name the same capture point');
|
|
137
|
+
assert.doesNotMatch(section, /sign(?:ed)? in to a project with your platform account/,
|
|
138
|
+
'an unqualified "project sign-in" also covers the command line, which records nothing (task 1004265)');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
t('the page tells a command-line-only builder that their sign-in records nothing, and why (task 1004265)', () => {
|
|
142
|
+
const section = termsHtml.slice(termsHtml.indexOf('Your work across projects'), termsHtml.indexOf('Fair use'));
|
|
143
|
+
assert.match(section, /Signing in from the command line does not record it/,
|
|
144
|
+
'a CLI-only builder stays unpublished, and the page must say so rather than leave them to guess');
|
|
145
|
+
assert.match(section, /on GitHub’s page, where these terms are not shown/,
|
|
146
|
+
'and why: the device approval never puts these terms in front of them');
|
|
135
147
|
});
|
|
136
148
|
|
|
137
149
|
t('the page says which acceptances were given on a builder’s behalf, and that the record marks them (task 1003360)', () => {
|
|
@@ -139,7 +151,7 @@ t('the page says which acceptances were given on a builder’s behalf, and that
|
|
|
139
151
|
'the owner chose to grandfather AND to say so on the page — the page must tell a pre-existing builder what was recorded for them');
|
|
140
152
|
assert.match(termsHtml, /marks that acceptance as grandfathered/i,
|
|
141
153
|
'and that the record keeps it distinguishable from one they gave');
|
|
142
|
-
assert.match(termsHtml, /your own acceptance replaces it the next time you sign in to a project/i,
|
|
154
|
+
assert.match(termsHtml, /your own acceptance replaces it the next time you sign in to a project in your browser/i,
|
|
143
155
|
'and what happens when they do sign in — the conflict branch below really does replace it');
|
|
144
156
|
assert.doesNotMatch(termsHtml, /written only by signing in/i,
|
|
145
157
|
'the page still says acceptance is written ONLY by signing in, which is false for every grandfathered account');
|
|
@@ -503,6 +515,100 @@ await ta('a session of an undeclared source (a leftover dev-box token) cannot mi
|
|
|
503
515
|
assert.equal(pool.accounts.size, 0, 'a session of an undeclared source recorded a platform T&C acceptance');
|
|
504
516
|
});
|
|
505
517
|
|
|
518
|
+
// The CLI's project sign-in (POST /sso/device/poll) also uses the platform account,
|
|
519
|
+
// and it deliberately records NOTHING (task 1004265). The approval happens on
|
|
520
|
+
// GitHub's device page, never on a hub page, so these terms are never in front of
|
|
521
|
+
// the person — and activation is ADR 0171 D3's "a human is demonstrably at the hub",
|
|
522
|
+
// which the same branch stamps. So the page names a BROWSER sign-in and says why a
|
|
523
|
+
// command-line one does not count; this drives the real route to hold that claim.
|
|
524
|
+
function post(path_, body) {
|
|
525
|
+
const payload = JSON.stringify(body);
|
|
526
|
+
return new Promise((resolve, reject) => {
|
|
527
|
+
const req = http.request({
|
|
528
|
+
host: '127.0.0.1', port, method: 'POST', path: path_,
|
|
529
|
+
headers: { 'content-type': 'application/json', 'content-length': Buffer.byteLength(payload) },
|
|
530
|
+
}, (res) => {
|
|
531
|
+
const chunks = [];
|
|
532
|
+
res.on('data', (c) => chunks.push(c));
|
|
533
|
+
res.on('end', () => {
|
|
534
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
535
|
+
let json = null; try { json = JSON.parse(text); } catch { /* not JSON */ }
|
|
536
|
+
resolve({ status: res.statusCode, json });
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
req.on('error', reject);
|
|
540
|
+
req.end(payload);
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// GitHub's side of the device flow, answered as approved for `identity`. The route
|
|
545
|
+
// reaches both modules through their exports objects, so this swaps the network leg
|
|
546
|
+
// and the signing key only — the route, its upsert and the fake pool stay real.
|
|
547
|
+
async function withApprovedDevice(identity, fn) {
|
|
548
|
+
const hubDevice = require('../modules/platform-identity/hub-device.js');
|
|
549
|
+
const hubKeys = require('../modules/platform-identity/hub-keys.js');
|
|
550
|
+
const saved = {
|
|
551
|
+
hubDeviceConfigured: hubDevice.hubDeviceConfigured,
|
|
552
|
+
pollHubGithubDevice: hubDevice.pollHubGithubDevice,
|
|
553
|
+
hubSigningConfigured: hubKeys.hubSigningConfigured,
|
|
554
|
+
mintHubAssertion: hubKeys.mintHubAssertion,
|
|
555
|
+
};
|
|
556
|
+
hubDevice.hubDeviceConfigured = () => true;
|
|
557
|
+
hubDevice.pollHubGithubDevice = async () => ({ state: 'ok', client_id: 'proj-a', identity });
|
|
558
|
+
hubKeys.hubSigningConfigured = () => true;
|
|
559
|
+
hubKeys.mintHubAssertion = () => 'ASSERTION';
|
|
560
|
+
try { return await fn(); } finally {
|
|
561
|
+
hubDevice.hubDeviceConfigured = saved.hubDeviceConfigured;
|
|
562
|
+
hubDevice.pollHubGithubDevice = saved.pollHubGithubDevice;
|
|
563
|
+
hubKeys.hubSigningConfigured = saved.hubSigningConfigured;
|
|
564
|
+
hubKeys.mintHubAssertion = saved.mintHubAssertion;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const CLI_IDENTITY = { github_id: '5151', github_login: 'cli-only', display_name: 'Cli Only', avatar_url: null };
|
|
569
|
+
|
|
570
|
+
await ta('a CLI-only project sign-in (the device poll) signs the builder in and records NO acceptance (task 1004265)', async () => {
|
|
571
|
+
SESSION = null;
|
|
572
|
+
pool.accounts.clear();
|
|
573
|
+
pool.calls.length = 0;
|
|
574
|
+
pool.setClock(NOW);
|
|
575
|
+
const res = await withApprovedDevice(CLI_IDENTITY, () => post('/sso/device/poll', { device_code: 'dc-1' }));
|
|
576
|
+
assert.equal(res.status, 200, 'CONTROL: the device poll must succeed, or the absence below proves nothing');
|
|
577
|
+
assert.equal(res.json && res.json.assertion, 'ASSERTION', 'CONTROL: the CLI got its sign-in assertion');
|
|
578
|
+
const row = pool.accounts.get('5151');
|
|
579
|
+
assert.ok(row, 'CONTROL: the device poll writes the platform account — the absence below is of the stamp, not the row');
|
|
580
|
+
assert.equal(row.terms_accepted_at, null,
|
|
581
|
+
'a command-line sign-in stamped an acceptance — nobody was shown the terms on that path; if this is now intended, /terms and ADR 0213 change with it');
|
|
582
|
+
assert.equal(row.terms_version, null);
|
|
583
|
+
assert.equal(row.profile_state, 'provisional', 'and it activates nothing (ADR 0171 D3: activation is a human at the hub)');
|
|
584
|
+
const upserts = pool.calls.filter((c) => /INSERT INTO platform_identity_accounts/i.test(c.sql) && /DO UPDATE/i.test(c.sql));
|
|
585
|
+
assert.equal(upserts.length, 1);
|
|
586
|
+
assert.equal(upserts[0].params[4], false, 'the device poll must pass the non-activating literal');
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
await ta('the device poll takes no acceptance from its body either — an extra field is refused before any write', async () => {
|
|
590
|
+
pool.accounts.clear();
|
|
591
|
+
const res = await withApprovedDevice(CLI_IDENTITY, () => post('/sso/device/poll', {
|
|
592
|
+
device_code: 'dc-2', activate: true, terms_accepted_at: '1999-01-01T00:00:00.000Z', terms_version: 'FORGED',
|
|
593
|
+
}));
|
|
594
|
+
assert.equal(res.status, 400, 'the strict validator must refuse fields the route does not declare');
|
|
595
|
+
assert.equal(pool.accounts.size, 0, 'a refused poll still wrote an account');
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
await ta('a CLI-only builder who later signs in to a project in the browser IS stamped then', async () => {
|
|
599
|
+
pool.accounts.clear();
|
|
600
|
+
pool.setClock(NOW);
|
|
601
|
+
await withApprovedDevice({ ...CLI_IDENTITY, github_id: '4242', github_login: 'octo' },
|
|
602
|
+
() => post('/sso/device/poll', { device_code: 'dc-3' }));
|
|
603
|
+
assert.equal(pool.accounts.get('4242').terms_accepted_at, null);
|
|
604
|
+
SESSION = HUB_SESSION;
|
|
605
|
+
pool.setClock(LATER);
|
|
606
|
+
assert.equal((await authorize()).status, 302);
|
|
607
|
+
const row = pool.accounts.get('4242');
|
|
608
|
+
assert.equal(row.terms_accepted_at, LATER, 'the browser sign-in the page names must stamp the account the CLI created');
|
|
609
|
+
assert.equal(row.profile_state, 'active');
|
|
610
|
+
});
|
|
611
|
+
|
|
506
612
|
// ===========================================================================
|
|
507
613
|
// 4. Idempotence — executed, not asserted against a string
|
|
508
614
|
// ===========================================================================
|