@bongos/core 1.19.410 → 1.19.412
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 +31 -21
- package/docs/adr/0203-doorway-changelog-out-of-module-api.md +54 -0
- package/docs/adr/README.md +1 -0
- package/docs/file-map.md +2 -1
- package/docs/module-api-changelog.md +1265 -0
- package/docs/modules-contract.md +2 -0
- package/docs/recipes/core-release-pipeline.md +3 -3
- package/docs/recipes/private-npm-distribution.md +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/bump-version.js +53 -25
- package/scripts/gds/deploy-divergence.js +1 -1
- package/scripts/gds/publish-manifest.js +6 -0
- package/src/bongos/module-scope-map.js +6 -1
- package/src/module-api.js +10 -1229
- package/tests/bump_version.mjs +72 -13
- package/tests/profile_route.mjs +290 -10
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.412",
|
|
6
|
+
"core_contract": "1.19.412",
|
|
7
|
+
"source_commit": "049b8f5c6bb893589c47e9e6e3855fc3da1bec06",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-
|
|
9
|
+
"built_at": "2026-08-29T15:07:18.728Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 354,
|
|
13
13
|
"agent_docs_stubbed": 23,
|
|
14
14
|
"functional_verbatim": 1667,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2044,
|
|
20
|
+
"tree_sha256": "d71641215ed53df26d8573408c98ba6afad6b1a95232f3dc1b8055688a98eb08",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -1514,10 +1514,15 @@
|
|
|
1514
1514
|
"mode": "0000644",
|
|
1515
1515
|
"sha256": "cb5bb269e40262b769bfa626fbc6d4ddf09a328b00742f07894c006b9b3bd885"
|
|
1516
1516
|
},
|
|
1517
|
+
{
|
|
1518
|
+
"path": "docs/adr/0203-doorway-changelog-out-of-module-api.md",
|
|
1519
|
+
"mode": "0000644",
|
|
1520
|
+
"sha256": "37c8ba1f75a3daac27d510e47f1dc392382084a726133db8d4e1db860031cca8"
|
|
1521
|
+
},
|
|
1517
1522
|
{
|
|
1518
1523
|
"path": "docs/adr/README.md",
|
|
1519
1524
|
"mode": "0000644",
|
|
1520
|
-
"sha256": "
|
|
1525
|
+
"sha256": "3195734df44b011f7b9e312b02aa20cc0bcbf02763c19046c6501935b5befbff"
|
|
1521
1526
|
},
|
|
1522
1527
|
{
|
|
1523
1528
|
"path": "docs/api-reference.md",
|
|
@@ -1852,17 +1857,22 @@
|
|
|
1852
1857
|
{
|
|
1853
1858
|
"path": "docs/file-map.md",
|
|
1854
1859
|
"mode": "0000644",
|
|
1855
|
-
"sha256": "
|
|
1860
|
+
"sha256": "0eda387feba9769e7bd939ec6072f2e562f54d896b56816272f351d8798cf125"
|
|
1856
1861
|
},
|
|
1857
1862
|
{
|
|
1858
1863
|
"path": "docs/handoff-template.md",
|
|
1859
1864
|
"mode": "0000644",
|
|
1860
1865
|
"sha256": "a60d85b8523b5944d4db8105b60166395ab9c1f931fb92f0f95a825b657fe277"
|
|
1861
1866
|
},
|
|
1867
|
+
{
|
|
1868
|
+
"path": "docs/module-api-changelog.md",
|
|
1869
|
+
"mode": "0000644",
|
|
1870
|
+
"sha256": "251455d2e8adfcad824b3ce55ba08418109cfb6e386990f3d9acfb551a992884"
|
|
1871
|
+
},
|
|
1862
1872
|
{
|
|
1863
1873
|
"path": "docs/modules-contract.md",
|
|
1864
1874
|
"mode": "0000644",
|
|
1865
|
-
"sha256": "
|
|
1875
|
+
"sha256": "bc9699e8ee97b5e2aa460533dd9a6dd249e340879bc1851359fd45d526f8b55b"
|
|
1866
1876
|
},
|
|
1867
1877
|
{
|
|
1868
1878
|
"path": "docs/onboarding/browser-terminal-guide.md",
|
|
@@ -1962,7 +1972,7 @@
|
|
|
1962
1972
|
{
|
|
1963
1973
|
"path": "docs/recipes/core-release-pipeline.md",
|
|
1964
1974
|
"mode": "0000644",
|
|
1965
|
-
"sha256": "
|
|
1975
|
+
"sha256": "5f272d8caf53bf1ceb49604996ea44375b1f9a9308fd3a7cac5a6f9a5982e142"
|
|
1966
1976
|
},
|
|
1967
1977
|
{
|
|
1968
1978
|
"path": "docs/recipes/devbox-app-release.md",
|
|
@@ -2047,7 +2057,7 @@
|
|
|
2047
2057
|
{
|
|
2048
2058
|
"path": "docs/recipes/private-npm-distribution.md",
|
|
2049
2059
|
"mode": "0000644",
|
|
2050
|
-
"sha256": "
|
|
2060
|
+
"sha256": "3c6613920881220ec4a076b4608ed57557d645c43dee3fbb4086ad4adb81f593"
|
|
2051
2061
|
},
|
|
2052
2062
|
{
|
|
2053
2063
|
"path": "docs/recipes/redteam-patrol.md",
|
|
@@ -5357,12 +5367,12 @@
|
|
|
5357
5367
|
{
|
|
5358
5368
|
"path": "package-lock.json",
|
|
5359
5369
|
"mode": "0000644",
|
|
5360
|
-
"sha256": "
|
|
5370
|
+
"sha256": "07258342132575cf206c98c5c145423c12a5b16f96c3ecf9c8a5c4c4265bcafa"
|
|
5361
5371
|
},
|
|
5362
5372
|
{
|
|
5363
5373
|
"path": "package.json",
|
|
5364
5374
|
"mode": "0000644",
|
|
5365
|
-
"sha256": "
|
|
5375
|
+
"sha256": "79513e9d85183a56152ef6bb5a75f61548efc663860f89c1b55df41d3ced73b2"
|
|
5366
5376
|
},
|
|
5367
5377
|
{
|
|
5368
5378
|
"path": "public-docs/index.html",
|
|
@@ -5932,7 +5942,7 @@
|
|
|
5932
5942
|
{
|
|
5933
5943
|
"path": "scripts/gds/bump-version.js",
|
|
5934
5944
|
"mode": "0000644",
|
|
5935
|
-
"sha256": "
|
|
5945
|
+
"sha256": "05866e29dd673180fd35fb6ae314b2b335670ff4f37049d737a8ad7c9d3c4acc"
|
|
5936
5946
|
},
|
|
5937
5947
|
{
|
|
5938
5948
|
"path": "scripts/gds/capture.js",
|
|
@@ -6057,7 +6067,7 @@
|
|
|
6057
6067
|
{
|
|
6058
6068
|
"path": "scripts/gds/deploy-divergence.js",
|
|
6059
6069
|
"mode": "0000644",
|
|
6060
|
-
"sha256": "
|
|
6070
|
+
"sha256": "4b77b2c878cace855ad979c66a7bbb0318199d10b1e0f114f79732db2b6cc203"
|
|
6061
6071
|
},
|
|
6062
6072
|
{
|
|
6063
6073
|
"path": "scripts/gds/design-sync.js",
|
|
@@ -6512,7 +6522,7 @@
|
|
|
6512
6522
|
{
|
|
6513
6523
|
"path": "scripts/gds/publish-manifest.js",
|
|
6514
6524
|
"mode": "0000644",
|
|
6515
|
-
"sha256": "
|
|
6525
|
+
"sha256": "27bf1a27785bfc18228e65649adce69f091592cf566ff89dcedffdf6022293dc"
|
|
6516
6526
|
},
|
|
6517
6527
|
{
|
|
6518
6528
|
"path": "scripts/gds/pulse.js",
|
|
@@ -7202,7 +7212,7 @@
|
|
|
7202
7212
|
{
|
|
7203
7213
|
"path": "src/bongos/module-scope-map.js",
|
|
7204
7214
|
"mode": "0000644",
|
|
7205
|
-
"sha256": "
|
|
7215
|
+
"sha256": "01c3c845f9c5bca78a6aa36a09327b0649e9dfaf7eec6f37ac279e2939c04723"
|
|
7206
7216
|
},
|
|
7207
7217
|
{
|
|
7208
7218
|
"path": "src/bongos/module-submissions.js",
|
|
@@ -7377,7 +7387,7 @@
|
|
|
7377
7387
|
{
|
|
7378
7388
|
"path": "src/module-api.js",
|
|
7379
7389
|
"mode": "0000644",
|
|
7380
|
-
"sha256": "
|
|
7390
|
+
"sha256": "b182b43409b6311ab968db425b6064378cc2842d9abc1f4628f18a3ea7cde9dc"
|
|
7381
7391
|
},
|
|
7382
7392
|
{
|
|
7383
7393
|
"path": "src/module-loader/catalog.js",
|
|
@@ -7797,7 +7807,7 @@
|
|
|
7797
7807
|
{
|
|
7798
7808
|
"path": "tests/bump_version.mjs",
|
|
7799
7809
|
"mode": "0000644",
|
|
7800
|
-
"sha256": "
|
|
7810
|
+
"sha256": "0d7bfd5a02e0beefe5f4a4b60daa4d3dee57f8e893febfd366732b419a75678f"
|
|
7801
7811
|
},
|
|
7802
7812
|
{
|
|
7803
7813
|
"path": "tests/cap_newcomer_tasks.mjs",
|
|
@@ -9372,7 +9382,7 @@
|
|
|
9372
9382
|
{
|
|
9373
9383
|
"path": "tests/profile_route.mjs",
|
|
9374
9384
|
"mode": "0000644",
|
|
9375
|
-
"sha256": "
|
|
9385
|
+
"sha256": "5af720ee7c18d4b47630fbbed7cb08901acfbf773960699e312496b8196c9fdc"
|
|
9376
9386
|
},
|
|
9377
9387
|
{
|
|
9378
9388
|
"path": "tests/profile_ui_cross_project.mjs",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 0203 — The doorway changelog leaves `src/module-api.js`: the CI carrier appends to markdown
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-08-28
|
|
5
|
+
- **Deciders:** the owner (Archon) — decision made directly on the incident: move the changelog out permanently and repoint the carrier; explicitly rejected trimming entries in place and raising the fitness baseline. Claude implemented.
|
|
6
|
+
- **Task:** task 1003335
|
|
7
|
+
- **Amends:** [ADR 0161](<redacted>.md) §2 (the CI auto-patch carrier's write target)
|
|
8
|
+
- **Interacts with:** [ADR 0083](<redacted>.md) (the doorway + `CORE_VERSION`), the `oversized_file_count` ratchet in `scripts/gds/fitness-ratchets.js` (task 1003129)
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
`CORE_VERSION` is the semver of the published module doorway `src/module-api.js`. Its release history lived in the same file, as a comment block between two `// ---` dividers directly above the literal — deliberately, so a bare version bump with no changelog line was impossible.
|
|
13
|
+
|
|
14
|
+
ADR 0161 then made **every merge to `main` publish**, and gave CI a carrier: when a merge lands with no human bump, `scripts/gds/bump-version.js` bumps the patch and appends a **two-line changelog entry**. That carrier commit is pushed by `github-actions[bot]` **straight to `main`** — it has to be, since the bump must precede the package step, and the default `GITHUB_TOKEN` cannot push past the required check. So the one writer that grows this file fastest is also the one writer that **does not pass through the `unit` gate**.
|
|
15
|
+
|
|
16
|
+
Two lines per release, one release per merge. On 2026-08-28 release **1.19.407** took `src/module-api.js` to **1501 lines** — one over the 1500-line `oversized_file_count` threshold. The consequences were structural, not cosmetic:
|
|
17
|
+
|
|
18
|
+
- `unit` went **red on `main`** (commit `4f99fa10`): `oversized_file_count regressed: 1 > baseline 0`, `excess_lines_total regressed: 2 > baseline 0`.
|
|
19
|
+
- Every **open PR inherited the red**, because `unit` builds the branch against current `main`. Four agents' work was parked behind it at once.
|
|
20
|
+
- The condition was **self-inflicting and monotonic**: each further release added two more lines, and the carrier could not be stopped by the very check it broke.
|
|
21
|
+
|
|
22
|
+
Of the file's 1501 lines, **1222 were changelog** — 448 released versions, the overwhelming majority of them one-per-merge carrier entries. The doorway's actual published surface is under 300 lines.
|
|
23
|
+
|
|
24
|
+
## Decision
|
|
25
|
+
|
|
26
|
+
**The release ledger moves out of `src/module-api.js` permanently, into markdown, and the carrier is repointed to write there.**
|
|
27
|
+
|
|
28
|
+
1. **New home: [`docs/module-api-changelog.md`](../module-api-changelog.md).** Markdown, not JavaScript. This is the load-bearing property, not a filing preference: `scripts/gds/fitness-ratchets.js` sizes `git ls-files '*.js'`, so a markdown ledger is **structurally exempt** from the line budget and can grow forever. Relocating to another `.js` file would only move the same time-bomb.
|
|
29
|
+
2. **The literal does not move.** `const CORE_VERSION` stays in `src/module-api.js` and stays the single source every reader parses. `deploy-divergence.js`, `package-core.js`, `publish.yml`, `module.js`, `init.js` and `provision-*.js` all read it exactly as before — the `^const CORE_VERSION = 'x.y.z';` line shape is unchanged, only its trailing comment now names the ledger's path.
|
|
30
|
+
3. **The history is preserved verbatim.** All 1222 lines / 448 versions moved byte-for-byte; only the `// ` comment marker that made each line a JS comment was stripped. The ledger sits in a fenced `text` block so the original hanging indentation survives markdown rendering intact. This is a release ledger, not scratch — nothing was summarised, trimmed, or reflowed.
|
|
31
|
+
4. **The insertion contract is unchanged.** Entries stay **oldest-first**, and the carrier inserts each new one **immediately above the divider that closes the ledger** — the same 75-dash divider, minus the `// `. `bump-version.js` throws rather than guess if that divider is missing, exactly as it did before.
|
|
32
|
+
5. **The carrier writes both files atomically-in-intent.** `bump-version.js --apply` reads *and transforms* both files before writing *either*, and refuses outright if the ledger transform did not happen. `publish.yml` stages both (`git add src/module-api.js docs/module-api-changelog.md`); `tests/bump_version.mjs` pins that staging list against the script so the two cannot drift.
|
|
33
|
+
6. **`src/module-api.js` keeps a pointer.** A short doc-comment where the block used to be says where the ledger went and why (ADR 0095 / `docs/code-conventions.md`) — someone will look for the history in the old place, and grep must answer them.
|
|
34
|
+
7. **The ledger still ships in the package.** `docs/` is default-deny in `PUBLISH_ALLOWLIST`, so the new file is registered explicitly. Without that line the history would silently stop reaching instances that install `@bongos/core` — today it reaches them inside `module-api.js`, and a module author checking what a `coreVersion` floor buys them is a real reader.
|
|
35
|
+
8. **The published copy is now genericized, and that is an improvement.** `package-core.js` treats a `.md` as a DOC: it runs mirror-redaction and any residual leak is fatal, where a `.js` shipped verbatim with brand strings as non-fatal advisories. So the ledger's historical mentions of the reference instance's brand and domains are rewritten to the neutral placeholders in the published core — which is what every other published doc already gets, and what a brand-neutral open-source core should carry. Verified by building the package: the no-leak gate passes and all 1255 lines ship.
|
|
36
|
+
|
|
37
|
+
### Rejected
|
|
38
|
+
|
|
39
|
+
- **Trim old entries in place.** Buys exactly one release, then the file crosses 1500 again. It also destroys ledger history to satisfy a size metric — the wrong thing to spend.
|
|
40
|
+
- **Raise the `oversized_file_count` baseline.** Out of policy: `config/fitness-baselines.json` says so in its own `_comment` ("Shrink-only — lower a value when the metric improves; raising one to pass CI is out of policy"), and the ratchet's whole purpose is that growth is not negotiable.
|
|
41
|
+
- **Exempt `src/module-api.js` from the ratchet.** Same objection, narrower blast radius: it would let the real doorway surface grow unwatched behind a changelog-shaped excuse.
|
|
42
|
+
- **Stop writing a changelog entry per release.** The entry is the provenance ADR 0161 §2 relies on and that `laneReleasedVersions()` reads release history from. The volume is a symptom of publish-on-merge working as designed, not a defect.
|
|
43
|
+
|
|
44
|
+
## Consequences
|
|
45
|
+
|
|
46
|
+
- `oversized_file_count` and `excess_lines_total` return to **0**; `src/module-api.js` drops from 1501 to **289** lines, leaving the doorway's real surface visible instead of buried under its own history.
|
|
47
|
+
- The failure mode is **eliminated, not deferred**. The ledger's growth rate is unchanged, but it no longer has a ceiling that a gate reads.
|
|
48
|
+
- **A version's history is one hop away** rather than inline. Mitigated by the pointer comment, the const line's trailing path, and the ledger's own header.
|
|
49
|
+
- **Two files now move per release** instead of one. The carrier commit's diff is slightly wider; the staging list is test-pinned so it cannot silently regress to one.
|
|
50
|
+
- ADR 0161 §2's sentence "bumps the patch and writes the changelog line" remains true — only the file it writes to changed. ADRs 0137 / 0161 / 0194 are historical records and were left as written; the operational instructions in `docs/recipes/core-release-pipeline.md` and `docs/recipes/private-npm-distribution.md` were repointed.
|
|
51
|
+
|
|
52
|
+
## When to revisit
|
|
53
|
+
|
|
54
|
+
If the ledger ever needs to be *queried* (release notes for a version range, a "what changed between my pin and latest" CLI), the fenced-text form is the wrong shape and it should become structured data (`docs/module-api-changelog.json` + a renderer). Nothing reads it programmatically today, so that stays YAGNI.
|
package/docs/adr/README.md
CHANGED
|
@@ -290,5 +290,6 @@ This keeps the decision history honest and traceable.
|
|
|
290
290
|
| 0200 | [**A mistyped bring-your-own domain can be corrected — the address it leaves is released to a blackhole, and the attach leg stops regenerating web.env from the row** ([task 1003237](https://cloudbongos.com/builders#/task/1003237), goal 1000058). `POST /provisioning/instances/:id/domain` refused a second address with a deliberate `409 domain_already_set` ("A genuine BYO address stays un-re-pointable, as before") while direction §8 said "attach/change stays for custom domains" — so a founder who mistyped one character in the create wizard was permanently addressed at a hostname they did not own, with no path back but teardown. Decisions: (1) a BYO address re-points under the guards the FIRST attach already applied — `isReservedHostname`, the task-1002704 in-apex squat rule, `getInstanceByDomain` uniqueness, `DOMAIN_ATTACH_FROM` (which already admitted `active`) — none added, none weakened; the platform-assigned `<slug>.<apex>` is un-re-pointable because the squat rule says so. (2) The address it leaves is RELEASED: `provisioning_012` adds `released_domains text[]`, written in the SAME statement as the new domain (a crash between the two would leave a hostname aimed at platform infra with nothing in the row to say so), an ARRAY because a founder can mistype twice before the runner drains. Only a BYO address is queued — the assigned `<slug>.<apex>` is the platform’s own name and the revive path re-uses it (ADR 0181 §2). (3) Release is a REPOINT to `192.0.2.1` (RFC 5737 TEST-NET-1), not a delete — the box lane’s idea-309 shape: a delete opens an NXDOMAIN window resolvers negative-cache for the zone’s SOA neg-TTL (~30 min, not editable), and an UPSERT needs only the contract every operator `BOX_DNS_HOOK` already implements. The Caddy vhost and the tls-check allow-list release THEMSELVES (the snippet is per-slug and carries the current domain; tls-check answers from the row). (4) A failed release is `ok:true` + `releaseFailed`, and KEEPS the queue so the next attach retries — a release that failed must never fail a re-point that already landed. (5) `domainAttachInstance` now patches web.env IN PLACE via `upsertEnvVars`/`originEnvVarsFor`, closing the ADR 0190 §2 hazard (idea 1000842) on this path: the template re-write regenerated the file FROM THE ROW, blanking the OAuth creds `placeManifestCreds` placed, the App private key and the federation block — masked for a FIRST attach by wizard order, and NOT masked for a re-point, which runs on a project the founder is already signed in to. Dry-run plans; an unreadable/empty file is refused, never patched. (6) A CHANGED domain clears `last_verified_{at,up}` — the overlay is a verdict on an ADDRESS (task 1002696), so carrying it would let the card claim the new name "last answered 2 minutes ago" when only the old one was ever probed (F16). (7) The card gains a third door — *Use a different domain*, pre-filled so a typo is edited not retyped — and says what it costs where the button is. Rejected: amending direction §8 to call the address fixed; deleting the old record; sequencing behind task 1002897; a `previous_domain` scalar (drops the middle address).](<redacted>.md) | provisioning / project lifecycle |
|
|
291
291
|
| 0201 | [**An application is the project's own `access_requests` row, vouched for by a hub-signed assertion carried in a HEADER; the record it carries is resolved live and never stored** ([task 1002283](https://cloudbongos.com/builders#/task/1002283), goal 1000045 — public builder profiles, C3/C4). The join relay (`POST /my-projects/join`) already posts `{github_login, display_name, note}` to the target's PUBLIC, unauthenticated `POST /access-requests` — presenting nothing the applicant could not have typed into the project's own landing page. Attaching a cross-project record to a login nobody vouched for turns the owner's queue into an impersonation surface: file a request naming a well-known builder, the owner reads that builder's track record beside it and approves, and whoever holds that GitHub account signs in. So the record is the thing that makes the unauthenticated write dangerous, and C4 cannot be built without closing it. Decisions: **D1** the application stays an `access_requests` row on the target — `status='invited'` IS what `hasInvitedAccessRequest` reads, so a parallel record would need a second branch in `firstTimeAdmissionBlocked`, the one decision that exists as one function to prevent drift; the migration adds only `applicant_github_id text` (core's own type) + `vouched_at`, the non-null id IS the vouch mark, and the console wave's `kind`/`created_by` stay a separate additive migration; the hub keeps a STATUSLESS echo `(github_id, client_id, applied_at)` so the applicant's own cards can say "you applied on <date>" without polling every project — it may never claim what the project decided (an approval becomes visible the way membership always does, via the check-in), and it ages out at 30 days; re-applying answers `requested`, not 409. **D2** the hub signs an audience-scoped `purpose: 'application'` assertion with the existing `mintHubAssertion`, verified OFFLINE by the existing `verifyHubAssertion` against the already-provisioned `<PREFIX>_HUB_PUBLIC_KEY` — no new secret, no apply-time hub call — and it travels in `<redacted>` because `validateOrRespond` is STRICT by default: a body field would 400 on every older pin, and `joinRelayOutcome` reads a 400 as "could not be reached", breaking applications to most projects for good (the CLI's device exchange carries its assertion in the body because that route was new; this one is not). A missing or invalid assertion writes the row UNVOUCHED, never refuses — refusing locks out an older hub and hands an attacker a denial vector. The record itself is never copied: the row stores an identity (+ the handle, since `GET /profiles/:handle` is the addressed read), and the REVIEWER'S BROWSER fetches the hub's already-public, already-CORS'd, already-`no-store` profile at render, where `profile_state='active' AND NOT hide_stats` is applied inside the module — so C2's live hide is honoured by construction with no cache to outlive it, and a hub outage degrades to "record unavailable" beside a queue that still works. An instance→hub server pull was rejected on ADR 0171 D1's own grounds. A private account's application carries name + handle + note in V1; the D3 sliver needs `project.recruit`, which the hub cannot check cross-origin. **D3** "project owner" is the project's OWN archon — the registrant is whoever `maybeSeatFirstAdmin` seated, delegates are whoever that archon grants on that instance, and because the instance IS the project the per-project-scoped-permission problem dissolves; the check is the atom that already guards the act, `access_request.review` (floor archon), and this goal mints NO new permission (widening the read half is the console wave's `project.recruit`). `platform_identity_projects.owner_github_id` stays advisory and is never a gate — a hub-held owner list consulted before an admission is the inversion ADR 0141 exists to prevent. **D4** three statuses, unchanged: `invited` IS the approval and the acceptance act is signing in (an `accepted` state would be a second place membership is asserted, free to drift from the one that admits); rescind is `invited → dismissed`, which the PATCH must learn to accept (it resolves only from `pending` today) and which must never pretend to remove a member who already signed in; an `invited` row expires read-time at 30 days whatever created it, while an application never expires because a stale `pending` admits nobody; approve/decline are idempotent on the value they hold. Rejected: a cross-project `applications` table on either side; a stored profile snapshot; the assertion in the body; refusing an unvouched application; the server-side pull; reading `owner_github_id` as authorization; a new "project owner" atom; an `accepted` status.](<redacted>.md) | platform identity / applications |
|
|
292
292
|
| 0202 | [**A connection is one directed row on the platform account, and every degree label is computed over the graph the viewer is allowed to see** ([task 1002294](https://cloudbongos.com/builders#/task/1002294), goal 1000045 criterion C6 — the design spike for the connections wave). Criterion C6 asks for LinkedIn-shaped connections; the cross-project data plane it must sit on is account-global (ADR 0141) and governed by an owner-signed privacy matrix (`docs/specs/<redacted>.md` D1/D2), where ADR 0171 D4 already bans "a count plus a hidden total" as a leak by subtraction. Decisions: (1) **one directed request row** on a new `platform_identity_connections` — `requester`/`addressee` kept because the inbox, cancel and cooldown all need to know who asked, with `pair_lo`/`pair_hi` GENERATED from LEAST/GREATEST and a partial unique index over `pending|accepted` so a duplicate AND a simultaneous reciprocal request are database errors, not route bugs; module-owned and `platform_identity_`-namespaced (ADR 0083 §5). (2) The `goal_membership_requests` lifecycle (`pending → accepted|rejected|cancelled`, atomic resolve-and-act) with three deliberate divergences: a decline is **silent**, a re-ask inside its 90-day cooldown is **swallowed and answered as if it worked** (ADR 0194 §3 applied to a person — a 409 saying "declined" would disclose what the silence protects), and pending requests expire at **30 days read-time** (privacy spec D4), with expiry resolved in the same statement that inserts, since `now()` cannot live in an index predicate. Remove **hard-deletes** — a "A removed B" tombstone is data neither party consented to keep and no read path uses. (3) Degree = a **recursive CTE seeded at the viewer**, `DEGREE_MAX = 3` with `FANOUT_1`/`FANOUT_2` caps and a deterministic frontier order; past the caps the label is `null` ("out of network"), never a number the query did not establish. Envelope stated honestly: single-digit ms at hub scale, caps bite around 10⁴ accounts, and they convert a hub-heavy account's millions-wide 3-hop into a *missing label* on a page that still renders. (4) Connections get **no predicate of their own** — they consume task 1002967's single effective-visibility reader, published as JS and as `accountVisibleSql(alias)` (the ADR 0182 form); `profile_state='active'` floors the feature, a private account answers **404 not 403** and never appears in a public list, `hide_stats` suppresses the numbers beside an edge but not the edge, degree is an **own-scope read** so viewer-relative labels coexist with viewer-independent public responses — and every count is the length of the array the viewer may see. (5) "Builders you may know" from mutuals + shared projects + recency, one explainable linear score, a named project only where its catalogue row is publicly listed; shared goals refused (instance-local), guilds a reserved empty slot, and **Discord refused outright** (outside the trust boundary; the hub stores no Discord identity), as are the GitHub follower graph and address-book import. Rejected: two mirrored rows on accept; a symmetric edge with no requester; a core table beside `builders`; a materialised closure/adjacency table (privacy-filtered at write time = a cached visibility decision, which ADR 0171 D2 forbids); an in-process graph cache; a graph database. Deferred and named: a connections-specific hide toggle, blocking, what an accepted connection unlocks on a private account, and notifications beyond the existing attention card. Exposes to the guild/orb wave: `neighbours`, `degreeBetween`, `mutualCount` — **not** a stored strength scalar.](<redacted>.md) | platform identity / privacy / social graph |
|
|
293
|
+
| 0203 | [**The doorway changelog leaves `src/module-api.js` — the CI auto-patch carrier appends to a markdown ledger instead** ([task 1003335](https://cloudbongos.com/builders#/task/1003335)). Amends [ADR 0161](<redacted>.md) §2. The `CORE_VERSION` release history lived as a comment block inside the doorway file, and ADR 0161's carrier appends two lines to it on EVERY merge-triggered release, pushed by `github-actions[bot]` straight to `main` — bypassing the `unit` gate it breaks. Release 1.19.407 took the file to 1501 lines, one over the `oversized_file_count` ratchet: `unit` went red on `main` and every open PR inherited it, self-inflicting and monotonic. Decision: the ledger moves to `docs/module-api-changelog.md` — markdown, which `fitness-ratchets.js` (`git ls-files '*.js'`) structurally never counts, so it can grow forever. All 1222 lines / 448 versions moved verbatim (only the `// ` marker stripped, kept in a fenced block so the hanging indent survives); the `const CORE_VERSION` literal and its line shape do NOT move, so every reader that greps it is untouched. `bump-version.js` transforms both files before writing either and refuses a half-applied bump; `publish.yml` stages both, pinned by `tests/bump_version.mjs`; the file is registered in `PUBLISH_ALLOWLIST` so the history keeps shipping inside `@bongos/core`; `src/module-api.js` keeps a pointer doc-comment where the block was. Rejected: trimming entries in place (buys one release), raising the baseline (out of policy per `config/fitness-baselines.json`'s own `_comment`), exempting the file from the ratchet.](<redacted>.md) | build pipeline / distribution |
|
|
293
294
|
|
|
294
295
|
> ⚠️ **Numbering collisions are now machine-enforced, not narrated.** Twenty numbers are shared by two ADRs each — assigned in parallel sessions before anything checked. The files keep their filenames (renumbering would break every existing citation, and a number once assigned is never reused), and this table disambiguates each pair as `NNNN-a` / `NNNN-b`. The authoritative list is `LEGACY_DUPLICATE_ADRS` in [`scripts/gds/adr-namespace.js`](../../scripts/gds/adr-namespace.js), frozen by exact filename: a **new** collision — or a third file joining a legacy number, or a rename of either half — hard-fails the `unit` CI gate, as does an index row that points at no file or an ADR with no row. The list may only shrink. This paragraph used to narrate the collisions one by one and had fallen eight behind reality; see [ADR 0195](<redacted>.md) for why the check exists and why the pairs are grandfathered rather than renumbered.
|
package/docs/file-map.md
CHANGED
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
│ ├── copy-registry.json ← GENERATED (scripts/gds/copy-inventory.js): the machine-readable copy registry — 1,096 user-facing strings with stable ids, render paths, and duplicates. R02's flag queue attaches to these ids; regenerate + commit, never hand-edit
|
|
58
58
|
│ ├── copy-inventory.md ← GENERATED twin of copy-registry.json: the human-readable copy report, including the "what this cannot see" section (server-side messages, skill prose, Discord copy, runtime-composed strings, and the src/ui-vs-reality surface mismatch)
|
|
59
59
|
│ ├── handoff-template.md ← session-end template + Definition of Done
|
|
60
|
+
│ ├── module-api-changelog.md ← the `CORE_VERSION` release ledger for the published doorway (ADR 0203, task 1003335). MOVED here out of src/module-api.js: the ADR 0161 CI carrier appends an entry on every release and pushes straight to main, which grew that .js file past the 1500-line oversized-file ratchet and turned `unit` red for main and every open PR. Markdown is exempt from the .js line budget. Written by scripts/gds/bump-version.js (entries oldest-first, each inserted above the closing divider); the CORE_VERSION literal itself stays in src/module-api.js
|
|
60
61
|
│ ├── google-chat-broadcast.md ← team-chat integration plan
|
|
61
62
|
│ ├── pms-v1-deploy.md ← step-by-step runbook to deploy PMS-V1 + status subdomain
|
|
62
63
|
│ ├── recipes/ ← long-form operational guides (formerly learnings/) — Postgres, Caddy, the pixel-art pipeline, etc.
|
|
@@ -199,7 +200,7 @@
|
|
|
199
200
|
│ ├── db.js ← GAME db helper: logEvent + player identity; sources its pool from src/bongos/pool.js (R52 carve-out, task 1191 — one pool, host→core)
|
|
200
201
|
│ ├── branding.js ← the branding contract resolver (env → config/branding.json → branding.neutral.json); single source for instance-identity strings + the configurable track set + db.database (ADR 0062 §3)
|
|
201
202
|
│ ├── modules.js ← back-compat facade over src/module-loader/loader.js; stable exports: isModuleEnabled/enabledModules/enabledDisciplines/clientModules/resolveModules; vanilla=all off (ADR 0062 §4; ADR 0083; docs/modules-contract.md)
|
|
202
|
-
│ ├── module-api.js ← THE PUBLISHED, SEMVER'D DOORWAY (ADR 0083): the ONLY core file a module may `require`. Re-exports kernel capabilities (auth gates, pool, db helpers, branding, seams, logger, CORE_VERSION). MINOR bump = additive export; MAJOR = breaking change; `bongos upgrade` pre-checks.
|
|
203
|
+
│ ├── module-api.js ← THE PUBLISHED, SEMVER'D DOORWAY (ADR 0083): the ONLY core file a module may `require`. Re-exports kernel capabilities (auth gates, pool, db helpers, branding, seams, logger, CORE_VERSION). MINOR bump = additive export; MAJOR = breaking change; `bongos upgrade` pre-checks. The release ledger is NOT here — it moved to docs/module-api-changelog.md (ADR 0203); only the `const CORE_VERSION` literal lives in this file.
|
|
203
204
|
│ ├── module-seams.js ← kernel seam registry (ADR 0083 / design 04§1): PORTS (registerProvider/resolve/resolveOptional — single-provider required capabilities) + EVENTS (emit/on — optional reactions, isolated errors). Modules cooperate through here, never by importing each other. Re-exported through module-api.js.
|
|
204
205
|
│ ├── module-loader/ ← the loader that makes `modules/<key>/` discoverable (BV1.R38–R41)
|
|
205
206
|
│ │ ├── loader.js ← discover modules/*/module.json → validate manifest → coreVersion-check → enabled-filter → mount routes behind kernel auth → start pollers. <redacted> on empty modules/. Used by modules.js + routes.js.
|