@bongos/core 1.20.69 → 1.20.71

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 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.20.69",
6
- "core_contract": "1.20.69",
7
- "source_commit": "983e206de19e3e452119fa087677995534a0bd91",
5
+ "core_version": "1.20.71",
6
+ "core_contract": "1.20.71",
7
+ "source_commit": "80b594f7c46b42161be5a9453989b09495783332",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-10-01T14:04:36.716Z",
9
+ "built_at": "2026-10-01T15:04:18.463Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 572,
13
13
  "agent_docs_stubbed": 27,
14
- "functional_verbatim": 2794,
14
+ "functional_verbatim": 2798,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 3394,
20
- "tree_sha256": "251c283dabfc92029abfd63749f8c964092c6110a6773d446852b4f8f11ca724",
19
+ "file_count": 3398,
20
+ "tree_sha256": "5a489808d7d33aa65f957bcb1aa21323044cafe05a72d5d7293b255966c007b9",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -317,12 +317,12 @@
317
317
  {
318
318
  "path": "clients/bongos-client/README.md",
319
319
  "mode": "0000644",
320
- "sha256": "3350163ed447189b523028f711e3ef1a400ea375ebe7123f2515add8b6a89de1"
320
+ "sha256": "472c0606ff4fe4e775d56e038702960834838d8767e984427f5de29d31f9cbe9"
321
321
  },
322
322
  {
323
323
  "path": "clients/bongos-client/bongos-client.global.js",
324
324
  "mode": "0000644",
325
- "sha256": "a863d3db1a112c490648e0f2b3eaddf3f2e8c9ebe107ec298ea5ff0c663a5e6a"
325
+ "sha256": "d641fbda06eb527c39d2eabbc7afc9f9182b03d766917e9fd84d69e86e9cc397"
326
326
  },
327
327
  {
328
328
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -332,17 +332,17 @@
332
332
  {
333
333
  "path": "clients/bongos-client/index.cjs",
334
334
  "mode": "0000644",
335
- "sha256": "06bf39230e1c813494dc85130694754d1eb6b3fd55d3e93a684dd238bf6bc22b"
335
+ "sha256": "73b143d7faa4d930ab82f9f31b178816cc5a8ea87754de7e0575441905d4562a"
336
336
  },
337
337
  {
338
338
  "path": "clients/bongos-client/index.d.ts",
339
339
  "mode": "0000644",
340
- "sha256": "2345d96c47f3851443f8b1adc5dac4556705e7f63f9875a4c62252bf833f17d4"
340
+ "sha256": "05ba628ec9c3761d8814af291cd5b11a02dd279c6e8df232b20ca632cc1e4336"
341
341
  },
342
342
  {
343
343
  "path": "clients/bongos-client/index.mjs",
344
344
  "mode": "0000644",
345
- "sha256": "313cfd428b7fd04a9fec6e56cdc1ddabb69af6ca144d7e09d2384a50d48b53df"
345
+ "sha256": "11a7eb441c5533244c695a4c60fe7b170e87eb4081af77703e796e8370e971e5"
346
346
  },
347
347
  {
348
348
  "path": "clients/bongos-client/package.json",
@@ -2262,17 +2262,17 @@
2262
2262
  {
2263
2263
  "path": "docs/api-reference.md",
2264
2264
  "mode": "0000644",
2265
- "sha256": "0abf904bcf32aef68bd70592d09cb986e4538cae62c2b9b268af8904d8a483fb"
2265
+ "sha256": "a24995419c2daa05deca5f2ed06656801c313f7499039a739b1bfa2cbc87e595"
2266
2266
  },
2267
2267
  {
2268
2268
  "path": "docs/api/openapi.json",
2269
2269
  "mode": "0000644",
2270
- "sha256": "026ea9ba339051ada00869b8363718fae4fcded3be6eae98bcc60a37b9e844dc"
2270
+ "sha256": "63946432b10d130a8f1749ced38bb733449ea4ed8039c9794287d3a269249b0c"
2271
2271
  },
2272
2272
  {
2273
2273
  "path": "docs/architecture.md",
2274
2274
  "mode": "0000644",
2275
- "sha256": "8b0fe800a7b4d60f4cb7f5eccd4fcab98d3e080a978ba3125dd9171c63cb5c78"
2275
+ "sha256": "3f0c53c83d5faed4198a251f09c3ffa057aa3dfaec9912d5fc884b0f1d602ebe"
2276
2276
  },
2277
2277
  {
2278
2278
  "path": "docs/branding-contract.md",
@@ -2802,12 +2802,12 @@
2802
2802
  {
2803
2803
  "path": "docs/module-api-changelog.md",
2804
2804
  "mode": "0000644",
2805
- "sha256": "36f8057dc29204b364c3d02c48b4ea21082a94915d187405dc863af09fda03d7"
2805
+ "sha256": "487634be3dd64633b2ee526720bff74171601bc1e58c02cfd605914bf8a9984b"
2806
2806
  },
2807
2807
  {
2808
2808
  "path": "docs/modules-contract.md",
2809
2809
  "mode": "0000644",
2810
- "sha256": "5d78d2fa2266bfed7e1034c0649274cb544333aa0c81ecdcb34413524729764f"
2810
+ "sha256": "33eb2665aea5cc00feb1de80b673f6063f98b2a8bd2caeb6fa4b09e41965c1df"
2811
2811
  },
2812
2812
  {
2813
2813
  "path": "docs/onboarding/diagrams/01-task-lifecycle.mmd",
@@ -9457,12 +9457,12 @@
9457
9457
  {
9458
9458
  "path": "package-lock.json",
9459
9459
  "mode": "0000644",
9460
- "sha256": "d67978a0c965aad91f26a8f1c1b8e913cca63e4aeafb8348bf842d817a5078a6"
9460
+ "sha256": "795a529e4e0cfa999a1e07d36b360e982ad712026d571679b59ca7202ffcb740"
9461
9461
  },
9462
9462
  {
9463
9463
  "path": "package.json",
9464
9464
  "mode": "0000644",
9465
- "sha256": "742449c7fddbb1eb1de87b87308a2cb3585f0a2e0b8ab5eba5818fbab42106f7"
9465
+ "sha256": "e3a6640cc49059ed01f82ddb1212d14d65f76e562d066aca5ff55c64117b9d19"
9466
9466
  },
9467
9467
  {
9468
9468
  "path": "public-docs/index.html",
@@ -9482,7 +9482,7 @@
9482
9482
  {
9483
9483
  "path": "release-notes.json",
9484
9484
  "mode": "0000644",
9485
- "sha256": "b4ccf7b529c34b659f29b69fb6d06b0b53b534469c637f3bc2f8bf62d0623e7a"
9485
+ "sha256": "ae2119391f14b5e1fda111e28b6cab08dd5ecb86826150cac145196b2f81b140"
9486
9486
  },
9487
9487
  {
9488
9488
  "path": "scripts/bongos-mcp.js",
@@ -10329,20 +10329,30 @@
10329
10329
  "mode": "0000644",
10330
10330
  "sha256": "7b10d8fd5146325c218d59eadfb6feaeb8819e14c4b27b166ad9ff714e1caed0"
10331
10331
  },
10332
+ {
10333
+ "path": "scripts/gds/module-assess-score.js",
10334
+ "mode": "0000644",
10335
+ "sha256": "526f3852778e708c6ffe4d6e0106a1617113e2e49aac8754b24321a68cddfaac"
10336
+ },
10332
10337
  {
10333
10338
  "path": "scripts/gds/module-assess-security.js",
10334
10339
  "mode": "0000644",
10335
- "sha256": "0dad366dcabf453ae276e074aafa6bd71223853a31cfe005dac6f3d713e12e4a"
10340
+ "sha256": "54a6c9c7ab8d0401eb5adf8b0025eac56f9c907ea19a868a38eb0d207befa058"
10336
10341
  },
10337
10342
  {
10338
10343
  "path": "scripts/gds/module-assess-tests.js",
10339
10344
  "mode": "0000644",
10340
- "sha256": "b86d6b3b98534c91b2dffe67f6c5335a09d2ef7c571c70e3a0871ab4929bc490"
10345
+ "sha256": "83dc9529be926f8e10043ab78d644d1a72096d02000623035798bd420b2b3261"
10346
+ },
10347
+ {
10348
+ "path": "scripts/gds/module-assess-version.js",
10349
+ "mode": "0000644",
10350
+ "sha256": "5891fdb5c464280801fbf401001d375ba93d5598d2190a9854f6dd2d61e0521b"
10341
10351
  },
10342
10352
  {
10343
10353
  "path": "scripts/gds/module.js",
10344
10354
  "mode": "0000644",
10345
- "sha256": "7ac7a4234d44c592f51a28d95a91f14379c6271977eb05d1e89700ba72827817"
10355
+ "sha256": "240a50d80078e81b692cea24d823340d797f3193afd6bec0dcb5d9afb0669c54"
10346
10356
  },
10347
10357
  {
10348
10358
  "path": "scripts/gds/move-escalation.js",
@@ -11147,7 +11157,7 @@
11147
11157
  {
11148
11158
  "path": "scripts/gds/upgrade.js",
11149
11159
  "mode": "0000644",
11150
- "sha256": "399c2225543fc0d37505bca9cd96e33cf5598aa1f364a458d5b5efb3a588ddb3"
11160
+ "sha256": "0646b9d86c01d190ed1b670694d2585827241b94792c70852b670a06327afb40"
11151
11161
  },
11152
11162
  {
11153
11163
  "path": "scripts/gds/validate-design.js",
@@ -11437,7 +11447,7 @@
11437
11447
  {
11438
11448
  "path": "src/bongos/module-store.js",
11439
11449
  "mode": "0000644",
11440
- "sha256": "6e058031cd08e741f970c6f4a535e36ff96bd61a34d335e72ab82d91e508d21f"
11450
+ "sha256": "4d4cb32e7fdc80c2f31c76a04d939c62980515eb06f7d3862a91c5163a9a70ce"
11441
11451
  },
11442
11452
  {
11443
11453
  "path": "src/bongos/module-submissions.js",
@@ -11587,7 +11597,7 @@
11587
11597
  {
11588
11598
  "path": "src/bongos/routes/modules.js",
11589
11599
  "mode": "0000644",
11590
- "sha256": "9a73d17319e72baaf1214bad5b8ae7847c8c11a4caa7cb7db74ef5b5dce1be8d"
11600
+ "sha256": "65dcf7b704d1fa321c128b36f3147bf23f54b976f60980450b2ed8a8583a302a"
11591
11601
  },
11592
11602
  {
11593
11603
  "path": "src/bongos/routes/my-sessions.js",
@@ -11662,7 +11672,7 @@
11662
11672
  {
11663
11673
  "path": "src/module-api.js",
11664
11674
  "mode": "0000644",
11665
- "sha256": "e1bae2a66ddf99dc54ceb55ce274d116780689f5ef224841d16106bc8b81701d"
11675
+ "sha256": "93d4c7e2e57b155565f9e995e8fe091e8c1782254ea9d06d29367fbcb404b1bb"
11666
11676
  },
11667
11677
  {
11668
11678
  "path": "src/module-loader/catalog.js",
@@ -14714,6 +14724,11 @@
14714
14724
  "mode": "0000644",
14715
14725
  "sha256": "9183d78e4d195428afbee8c71746e12db2455f8529ac1223d690a7b8f7ded538"
14716
14726
  },
14727
+ {
14728
+ "path": "tests/module_assess_score.mjs",
14729
+ "mode": "0000644",
14730
+ "sha256": "fd919118055c14147c9b4d7649622c1ebb47ba48336d84fe2c2a35f859a20dd6"
14731
+ },
14717
14732
  {
14718
14733
  "path": "tests/module_assess_security.mjs",
14719
14734
  "mode": "0000644",
@@ -14742,7 +14757,7 @@
14742
14757
  {
14743
14758
  "path": "tests/module_cli.mjs",
14744
14759
  "mode": "0000644",
14745
- "sha256": "cc3a4259d03582ca93287271ddc95bbeaea76447e104b8fb0f33aa6b154c8e7c"
14760
+ "sha256": "18fa817150d1d390f5f1c44651aea7e667227c8063393b2d0f82ff0b9f7fbaa8"
14746
14761
  },
14747
14762
  {
14748
14763
  "path": "tests/module_contributions.mjs",
@@ -14824,6 +14839,11 @@
14824
14839
  "mode": "0000644",
14825
14840
  "sha256": "1b50c9f68bfe731b29ddcce6947847b6e6f3f7bc5b0a08bbacc4afb25d5a3d90"
14826
14841
  },
14842
+ {
14843
+ "path": "tests/module_upgrade_updates.mjs",
14844
+ "mode": "0000644",
14845
+ "sha256": "7260dabcf71a69d4ce41609e8a88c94c112fdda354f774dadf0a2648f4feacaf"
14846
+ },
14827
14847
  {
14828
14848
  "path": "tests/modules.mjs",
14829
14849
  "mode": "0000644",
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
5
5
  by hand; it regenerates when the spec changes, so it can never drift from the routes.
6
6
 
7
7
  - API version: **v1** (served at `/api/bongos/v1`)
8
- - 485 operations across 73 resource groups
8
+ - 486 operations across 73 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -1087,6 +1087,8 @@ function createClient(opts = {}) {
1087
1087
  getStoreModulesKeyVersionsVersionHowto: (args) => request("GET", "/store/modules/{key}/versions/{version}/howto", { hasBody: false }, args),
1088
1088
  // GET /store/modules/{key}/versions/{version}/tarball — rank: any-builder — GET /store/modules/:key/versions/:version/tarball
1089
1089
  getStoreModulesKeyVersionsVersionTarball: (args) => request("GET", "/store/modules/{key}/versions/{version}/tarball", { hasBody: false }, args),
1090
+ // GET /store/modules/latest — rank: any-builder — GET /store/modules/latest
1091
+ getStoreModulesLatest: (args) => request("GET", "/store/modules/latest", { hasBody: false }, args),
1090
1092
  },
1091
1093
  "taskRecommendations": {
1092
1094
  // POST /task-recommendations — rank: any-builder — POST /task-recommendations
@@ -1086,6 +1086,8 @@ function createClient(opts = {}) {
1086
1086
  getStoreModulesKeyVersionsVersionHowto: (args) => request("GET", "/store/modules/{key}/versions/{version}/howto", { hasBody: false }, args),
1087
1087
  // GET /store/modules/{key}/versions/{version}/tarball — rank: any-builder — GET /store/modules/:key/versions/:version/tarball
1088
1088
  getStoreModulesKeyVersionsVersionTarball: (args) => request("GET", "/store/modules/{key}/versions/{version}/tarball", { hasBody: false }, args),
1089
+ // GET /store/modules/latest — rank: any-builder — GET /store/modules/latest
1090
+ getStoreModulesLatest: (args) => request("GET", "/store/modules/latest", { hasBody: false }, args),
1089
1091
  },
1090
1092
  "taskRecommendations": {
1091
1093
  // POST /task-recommendations — rank: any-builder — POST /task-recommendations
@@ -167,6 +167,7 @@ export interface GetSpecialitiesResponse { specialities: unknown }
167
167
  export interface GetSsoPubkeyResponse { alg: unknown; format: unknown; public_key_b64: unknown }
168
168
  export interface GetStoreEntitlementsResponse { entitlements: unknown }
169
169
  export interface GetStoreModulesKeyVersionsVersionHowtoResponse { module_key: unknown; title: unknown; version: unknown; published_at: unknown; delisted: unknown; markdown: unknown; artifact_url: unknown }
170
+ export interface GetStoreModulesLatestResponse { latest: unknown }
170
171
  export interface GetTaskRecommendationsForMeResponse { recommendations: unknown; count: unknown }
171
172
  export interface GetTaskRecommendationsMineResponse { recommendations: unknown; count: unknown }
172
173
  export interface GetTasksClaimableResponse { claimable: unknown; claimable_total: unknown; active_claims: unknown }
@@ -1533,6 +1534,8 @@ export interface BongosClient {
1533
1534
  getStoreModulesKeyVersionsVersionHowto(args?: RequestArgs): Promise<GetStoreModulesKeyVersionsVersionHowtoResponse>;
1534
1535
  /** GET /store/modules/{key}/versions/{version}/tarball — rank: any-builder */
1535
1536
  getStoreModulesKeyVersionsVersionTarball(args?: RequestArgs): Promise<ApiResponse>;
1537
+ /** GET /store/modules/latest — rank: any-builder */
1538
+ getStoreModulesLatest(args?: RequestArgs): Promise<GetStoreModulesLatestResponse>;
1536
1539
  };
1537
1540
  "taskRecommendations": {
1538
1541
  /** POST /task-recommendations — rank: any-builder */
@@ -1083,6 +1083,8 @@ export function createClient(opts = {}) {
1083
1083
  getStoreModulesKeyVersionsVersionHowto: (args) => request("GET", "/store/modules/{key}/versions/{version}/howto", { hasBody: false }, args),
1084
1084
  // GET /store/modules/{key}/versions/{version}/tarball — rank: any-builder — GET /store/modules/:key/versions/:version/tarball
1085
1085
  getStoreModulesKeyVersionsVersionTarball: (args) => request("GET", "/store/modules/{key}/versions/{version}/tarball", { hasBody: false }, args),
1086
+ // GET /store/modules/latest — rank: any-builder — GET /store/modules/latest
1087
+ getStoreModulesLatest: (args) => request("GET", "/store/modules/latest", { hasBody: false }, args),
1086
1088
  },
1087
1089
  "taskRecommendations": {
1088
1090
  // POST /task-recommendations — rank: any-builder — POST /task-recommendations
@@ -19794,6 +19794,44 @@
19794
19794
  ]
19795
19795
  }
19796
19796
  },
19797
+ "/store/modules/latest": {
19798
+ "get": {
19799
+ "operationId": "get_store_modules_latest",
19800
+ "tags": [
19801
+ "store"
19802
+ ],
19803
+ "summary": "GET /store/modules/latest",
19804
+ "description": "The newest published version of each named module — what `bongos upgrade` compares an instance's installed store modules against to report the updates available (task 1003787). `?keys=a,b,c`, at most STORE_LATEST_MAX_KEYS. rank: any-builder — a read of public store metadata (version numbers and the core range each needs, the same facts the how-to page shows). It takes no entitlement and changes nothing, unlike acquire; a key the store does not know is simply absent from the answer.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
19805
+ "x-rank": "any-builder",
19806
+ "x-source": "src/bongos/routes/modules.js",
19807
+ "responses": {
19808
+ "200": {
19809
+ "description": "Success.",
19810
+ "content": {
19811
+ "application/json": {
19812
+ "schema": {
19813
+ "$ref": "#/components/schemas/GetStoreModulesLatestResponse"
19814
+ }
19815
+ }
19816
+ }
19817
+ },
19818
+ "400": {
19819
+ "$ref": "#/components/responses/BadRequest"
19820
+ },
19821
+ "401": {
19822
+ "$ref": "#/components/responses/Unauthorized"
19823
+ },
19824
+ "403": {
19825
+ "$ref": "#/components/responses/Forbidden"
19826
+ }
19827
+ },
19828
+ "security": [
19829
+ {
19830
+ "builderSession": []
19831
+ }
19832
+ ]
19833
+ }
19834
+ },
19797
19835
  "/store/modules/{key}/acquire": {
19798
19836
  "post": {
19799
19837
  "operationId": "post_store_modules_key_acquire",
@@ -24851,6 +24889,15 @@
24851
24889
  "artifact_url"
24852
24890
  ]
24853
24891
  },
24892
+ "GetStoreModulesLatestResponse": {
24893
+ "type": "object",
24894
+ "properties": {
24895
+ "latest": {}
24896
+ },
24897
+ "required": [
24898
+ "latest"
24899
+ ]
24900
+ },
24854
24901
  "GetTaskRecommendationsForMeResponse": {
24855
24902
  "type": "object",
24856
24903
  "properties": {
@@ -30997,9 +31044,9 @@
30997
31044
  "description": "A required dependency/feature is not configured or is temporarily down."
30998
31045
  }
30999
31046
  },
31000
- "x-endpoint-count": 485,
31001
- "x-schema-count": 513,
31047
+ "x-endpoint-count": 486,
31048
+ "x-schema-count": 514,
31002
31049
  "x-undocumented-bodies": 12,
31003
- "x-response-schemas": 343,
31050
+ "x-response-schemas": 344,
31004
31051
  "x-generated-by": "scripts/gds/gen-api-docs.js"
31005
31052
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Bongos API reference
4
4
 
5
- > **Generated from the live route files** — the route file is authoritative. 485 endpoints across 89 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 486 endpoints across 89 route files.
6
6
  > Machine-readable spec: [`docs/api/openapi.json`](api/openapi.json) (OpenAPI 3.1). Rendered docs site: **`/docs`** (e.g. `cloudbongos.com/docs`).
7
7
 
8
8
  Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust-boundary-server-enforced-permissions.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -769,7 +769,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
769
769
  | GET | `/api/bongos/sso/pubkey` | `public` | — | GET /sso/pubkey — the hub's Ed25519 assertion-verification key (public). |
770
770
  | POST | `/api/bongos/sso/token` | `public` | `client_id`, `client_secret`, `code`, `redirect_uri` | POST /sso/token — server-to-server code redemption. |
771
771
 
772
- ## `store` (7)
772
+ ## `store` (8)
773
773
 
774
774
  | Method | Path | Rank | Body | Description |
775
775
  |---|---|---|---|---|
@@ -780,6 +780,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
780
780
  | POST | `/api/bongos/store/modules/:key/versions` | `metic+archon` | _undocumented_ | POST /api/bongos/store/modules/:key/versions — publish one module version to the store (task 1004271, ADR 0338 D1). |
781
781
  | GET | `/api/bongos/store/modules/:key/versions/:version/howto` | `any-builder` | — | GET /api/bongos/store/modules/:key/versions/:version/howto — the how-to a version shipped with (task 1004366, ADR 0347 D1/D3), read from … |
782
782
  | GET | `/api/bongos/store/modules/:key/versions/:version/tarball` | `any-builder` | — | |
783
+ | GET | `/api/bongos/store/modules/latest` | `any-builder` | — | The newest published version of each named module — what `bongos upgrade` compares an instance's installed store modules against to repor… |
783
784
 
784
785
  ## `task-recommendations` (4)
785
786
 
@@ -273,7 +273,7 @@ module_assessment_scores(id, version_id, kind IN (computed|override), overall 0-
273
273
  -- and is a new row on the computed history, never an edit (D6)
274
274
  ```
275
275
 
276
- Signals that fill it: **Tests** — `scripts/gds/module-assess-tests.js <version id>` (task 1003791) unpacks the published tarball to `<core root>/.module-assess-<run>/<key>/` (gitignored, removed after), runs each `tests/*.mjs` in its own node process with a timeout and a credential-free environment — regardless of `isModuleEnabled`, which skips every default-off catalog module in the unit gate — and appends one `tests` row: `scored` = % of test files passing (sample_size = files), `no_data` = declares no tests, `not_scored` = tarball unreadable. The store path **refuses unless `MODULE_TEST_SANDBOX=1`** — a published module's tests run only in a separate testing environment with no secrets on disk, never on the control plane (owner, 2026-09-30). `--dir modules/<key>` is a DB-free dry run on your own checkout. Nothing calls it on publish yet (task 1003794 wires that). **Security** — `scripts/gds/module-assess-security.js <version id>` (task 1003792, ADR 0343 D2 gate) appends one `security` row, `passed`/`failed` only: fails on a publish-denylist file, a `module.json` dependency fetched outside the registry (an allowlist: a plain npm name with a plain semver range or dist-tag, anything else fails and is never handed to npm), or a high/critical `npm audit` advisory (resolved metadata-only with `--ignore-scripts`; nothing of the module runs, so it is control-plane safe). An audit that cannot run is `not_scored` — the gate stays shut. Floating ranges and the `maintenance` posture (ADR 0166) are noted in `detail`, never failed on.
276
+ Signals that fill it: **Tests** — `scripts/gds/module-assess-tests.js <version id>` (task 1003791) unpacks the published tarball to `<core root>/.module-assess-<run>/<key>/` (gitignored, removed after), runs each `tests/*.mjs` in its own node process with a timeout and a credential-free environment — regardless of `isModuleEnabled`, which skips every default-off catalog module in the unit gate — and appends one `tests` row: `scored` = % of test files passing (sample_size = files), `no_data` = declares no tests, `not_scored` = tarball unreadable. The store path **refuses unless `MODULE_TEST_SANDBOX=1`** — a published module's tests run only in a separate testing environment with no secrets on disk, never on the control plane (owner, 2026-09-30). `--dir modules/<key>` is a DB-free dry run on your own checkout. On publish the version's Tests part is recorded `pending` until that environment runs it. **Security** — `scripts/gds/module-assess-security.js <version id>` (task 1003792, ADR 0343 D2 gate) appends one `security` row, `passed`/`failed` only: fails on a publish-denylist file, a `module.json` dependency fetched outside the registry (an allowlist: a plain npm name with a plain semver range or dist-tag, anything else fails and is never handed to npm), or a high/critical `npm audit` advisory (resolved metadata-only with `--ignore-scripts`; nothing of the module runs, so it is control-plane safe). An audit that cannot run is `not_scored` — the gate stays shut. Floating ranges and the `maintenance` posture (ADR 0166) are noted in `detail`, never failed on. **Score** — `scripts/gds/module-assess-score.js` (task 1003794) composes a version's newest signal per part into a `module_assessment_scores` row: `security_passed` from the gate (NULL = not run), `overall` = the plain average of the SCORED parts among Tests, Install, Reliability and Tester feedback (a part with no data is left out, never zero; none → NULL), Docs shown but never averaged, `is_new` until Install or Reliability is scored, plus the signal ids and a readable `formula`. A recompose that would repeat the current score writes nothing. Both signal CLIs recompose after recording, and the store's publish route queues `assessVersion` after answering the author (one at a time per process, at most 20 waiting; past that it is logged as not assessed): Tests `pending` (only if no Tests result exists), the Security gate, then the score. `node scripts/gds/module-assess-version.js <id>` re-runs it by hand (`scripts/gds/module-assess-version.js` holds the publish-time half, apart from the composer so the signal CLIs recompose without a require cycle).
277
277
 
278
278
  Code: `src/bongos/module-entitlements.js` (`grantEntitlement`, `recordAcquired`, `revokeEntitlement`, `checkEntitlement`, `listEntitlements`). Read routes (own-scoped, `requireBuilder`): `GET /store/entitlements`, `GET /store/modules/:key/entitlement`. Install (task 1003785) grants a free module through `POST /store/modules/:key/acquire`; the buy action (area 8) will grant a paid one.
279
279
 
@@ -2795,5 +2795,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
2795
2795
  landed since 1.20.67 with no explicit bump. run 36871565601. (task 1002620)
2796
2796
  1.20.69 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2797
2797
  landed since 1.20.68 with no explicit bump. run 36873353617. (task 1002620)
2798
+ 1.20.70 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2799
+ landed since 1.20.69 with no explicit bump. run 36877499272. (task 1002620)
2800
+ 1.20.71 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2801
+ landed since 1.20.70 with no explicit bump. run 36881290177. (task 1002620)
2798
2802
  ---------------------------------------------------------------------------
2799
2803
  ```
@@ -380,6 +380,8 @@ Run `bongos upgrade` to confirm coreVersion compatibility, then `node scripts/gd
380
380
  - The new version is written beside the old one and swapped in; any failure leaves the installed version in place. Files the new version dropped are gone afterwards.
381
381
  - The on/off switch is untouched. A module bundled with the core is refused; it updates with the core (`bongos upgrade`).
382
382
 
383
+ **`bongos upgrade` says which installed modules have an update** (task 1003787), below its compatibility rows, so one command answers "what is stale here" for the core and its modules. It asks `GET /store/modules/latest?keys=…` for the newest version of every module here with an exact version — a read that takes no entitlement — and lists each newer one with `bongos module update <key>`, or says it waits for the core when that version needs a newer one. A delisted module is flagged as getting no further versions (ADR 0338 D2). None of this changes the exit code: an incompatible enabled module still blocks and nothing else does. With no session or no reachable store it says "not checked" and the pre-check stands; `--no-store` skips the read.
384
+
383
385
  ## Carving an existing core domain (the `db.js` per-domain pattern)
384
386
 
385
387
  Most BONGOS-V1 module work is not scaffolding a *new* module — it's **carving an existing core domain out of the monolith** (ADR 0091, criterion C7). The reference carve is the kernel slice `src/bongos/db-kernel.js` (BV1.R69); the feature precedents are `modules/discord/db.js` + `modules/game/db.js`. Every later carve (memory R72, grading R73, …) copies this recipe. The invariant is **OTB byte-identical** at every step — you are *moving* code, not changing behavior.
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.20.69",
3
+ "version": "1.20.71",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.20.69",
9
+ "version": "1.20.71",
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.69",
3
+ "version": "1.20.71",
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",
@@ -8543,5 +8543,17 @@
8543
8543
  "id": "1004490",
8544
8544
  "text": "Session notes for today's account-page work are on file, so the next session can pick up without re-discovering what was done."
8545
8545
  }
8546
+ ],
8547
+ "1.20.70": [
8548
+ {
8549
+ "id": "1003787",
8550
+ "text": "Running 'bongos upgrade' now also tells you which installed modules have a newer version in the store, and the command to update each one. It never stops an upgrade on that account."
8551
+ }
8552
+ ],
8553
+ "1.20.71": [
8554
+ {
8555
+ "id": "1003794",
8556
+ "text": "Each module version in the store now gets one overall score built from its separate checks, and a newly published version is checked automatically. A version with no real-world data yet is marked New instead of scoring low."
8557
+ }
8546
8558
  ]
8547
8559
  }
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ // scripts/gds/module-assess-score.js — compose a store version's assessment
3
+ // signals into its one overall score (task 1003794; ADR 0343 D2/D3/D5, ADR 0347 D5; tables from core_265).
4
+ //
5
+ // WHY one composer. The floor, the ranking and the cap (tasks 1003807-9) all read
6
+ // one number, and an author appealing it must be able to redo the sum. So the rule
7
+ // lives here once, as a pure function, and every writer of a signal calls the same
8
+ // recompose afterwards:
9
+ // - Security is a GATE (D2): it sets security_passed (true / false / NULL = not
10
+ // run or could not run) and is never averaged in.
11
+ // - overall = the plain, unweighted average of the parts that are SCORED among
12
+ // Tests, Install, Reliability and Tester feedback (D3). A part with no data —
13
+ // no row, or no_data / pending / not_scored — is left out, never a zero.
14
+ // No such part at all → overall NULL.
15
+ // - Docs is shown with the parts and never averaged (ADR 0347 D5).
16
+ // - is_new (D5): the version has no scored Install or Reliability part yet.
17
+ // The CURRENT result of a part is its newest signal row (core_265). Each score
18
+ // row names the signal ids it was composed from and a formula a person can read,
19
+ // so "why did I score 71?" is answered by the row. A recompose that would write
20
+ // the same score as the current computed row writes nothing, so the history only
21
+ // moves when the answer does.
22
+ //
23
+ // Re-assessment on publish lives in module-assess-version.js, which runs the
24
+ // Security gate and then this recompose; it is a separate file so the signal
25
+ // CLIs can call recompose without a require cycle.
26
+ //
27
+ // Both reads are served by core_265's indexes: signals on (version_id, part,
28
+ // measured_at DESC, id DESC), scores on (version_id, computed_at DESC, id DESC).
29
+ //
30
+ // node scripts/gds/module-assess-score.js <store_module_versions.id> recompose + print
31
+
32
+ const AVERAGED = ['tests', 'install', 'reliability', 'tester_feedback'];
33
+ const REAL_WORLD = ['install', 'reliability'];
34
+ const LABEL = { security: 'Security', tests: 'Tests', install: 'Install', reliability: 'Reliability', tester_feedback: 'Tester feedback', docs: 'Docs' };
35
+
36
+ // Compose from the CURRENT signal per part ({ [part]: row }), pure. Returns the
37
+ // fields of a module_assessment_scores row.
38
+ function composeScore(current = {}) {
39
+ const sec = current.security;
40
+ const securityPassed = sec && sec.outcome === 'passed' ? true : sec && sec.outcome === 'failed' ? false : null;
41
+ const used = AVERAGED.filter((p) => current[p] && current[p].outcome === 'scored' && current[p].score != null);
42
+ const overall = used.length
43
+ ? Math.round(used.reduce((sum, p) => sum + Number(current[p].score), 0) / used.length)
44
+ : null;
45
+ const isNew = !REAL_WORLD.some((p) => used.includes(p));
46
+
47
+ const gate = securityPassed === true ? 'Security passed' : securityPassed === false ? 'Security FAILED (not listed, whatever the score)' : 'Security not checked yet';
48
+ const sum = used.length
49
+ ? `overall ${overall} = average of ${used.map((p) => `${LABEL[p]} ${current[p].score}`).join(', ')}`
50
+ : 'no overall score yet: no averaged part has data';
51
+ const left = AVERAGED.filter((p) => !used.includes(p));
52
+ const formula = `${gate}; ${sum}${left.length ? `; left out (no data): ${left.map((p) => LABEL[p]).join(', ')}` : ''}${isNew ? '; labelled New' : ''}`;
53
+
54
+ const signalIds = [sec, ...used.map((p) => current[p])].filter(Boolean).map((r) => Number(r.id)).sort((a, b) => a - b);
55
+ return { overall, security_passed: securityPassed, is_new: isNew, formula, signal_ids: signalIds };
56
+ }
57
+
58
+ const sameScore = (a, b) => !!a && !!b
59
+ && (a.overall == null ? null : Number(a.overall)) === b.overall
60
+ && a.security_passed === b.security_passed
61
+ && a.is_new === b.is_new
62
+ && (a.signal_ids || []).map(Number).join(',') === b.signal_ids.join(',');
63
+
64
+ // Read a version's current signal per part, compose, and append a computed score
65
+ // row unless it would repeat the current one. Resolves { ok, score, written }.
66
+ async function recomposeScore(versionId, { db } = {}) {
67
+ const pool = db || require('../../src/bongos/pool').pool;
68
+ const { rows } = await pool.query(
69
+ `SELECT DISTINCT ON (part) id, part, outcome, score, sample_size
70
+ FROM module_assessment_signals WHERE version_id = $1
71
+ ORDER BY part, measured_at DESC, id DESC`, [versionId]);
72
+ const current = {};
73
+ for (const r of rows) current[r.part] = r;
74
+ const next = composeScore(current);
75
+
76
+ const { rows: [last] } = await pool.query(
77
+ `SELECT id, overall, security_passed, is_new, signal_ids FROM module_assessment_scores
78
+ WHERE version_id = $1 AND kind = 'computed' ORDER BY computed_at DESC, id DESC LIMIT 1`, [versionId]);
79
+ if (sameScore(last, next)) return { ok: true, score: { ...last, formula: next.formula }, written: false };
80
+
81
+ const { rows: [row] } = await pool.query(
82
+ `INSERT INTO module_assessment_scores (version_id, kind, overall, security_passed, is_new, formula, signal_ids)
83
+ VALUES ($1, 'computed', $2, $3, $4, $5, $6)
84
+ RETURNING id, version_id, overall, security_passed, is_new, formula, signal_ids, computed_at`,
85
+ [versionId, next.overall, next.security_passed, next.is_new, next.formula, next.signal_ids]);
86
+ return { ok: true, score: row, written: true };
87
+ }
88
+
89
+ // After a signal CLI records a row: re-compose and print the score line.
90
+ async function printRecomposed(versionId) {
91
+ const { score } = await recomposeScore(versionId);
92
+ console.log(` score: ${score.formula}`);
93
+ }
94
+
95
+ async function main(argv) {
96
+ const id = argv[0];
97
+ if (!/^\d+$/.test(String(id || ''))) {
98
+ console.error('usage: node scripts/gds/module-assess-score.js <store_module_versions.id>');
99
+ return 2;
100
+ }
101
+ const res = await recomposeScore(id);
102
+ if (!res.ok) { console.error(res.message); return 1; }
103
+ console.log(`version ${id}: ${res.score.formula}`);
104
+ return 0;
105
+ }
106
+
107
+ if (require.main === module) {
108
+ main(process.argv.slice(2)).then((code) => { process.exitCode = code; }, (e) => { console.error(e.stack || e.message); process.exitCode = 1; });
109
+ }
110
+
111
+ module.exports = { composeScore, recomposeScore, printRecomposed };
@@ -241,6 +241,7 @@ async function main(argv) {
241
241
  if (!res.ok) { console.error(res.message); return 1; }
242
242
  const s = res.signal;
243
243
  console.log(`${res.version.module_key} ${res.version.version}: security ${s.outcome} — ${s.reason} (signal ${s.id})`);
244
+ await require('./module-assess-score').printRecomposed(res.version.id); // new data re-composes the score (task 1003794)
244
245
  return 0;
245
246
  }
246
247
 
@@ -238,6 +238,7 @@ async function main(argv) {
238
238
  if (!res.ok) { console.error(res.message); return 1; }
239
239
  const s = res.signal;
240
240
  console.log(`${res.version.module_key} ${res.version.version}: tests ${s.outcome}${s.score !== null ? ` ${s.score}/100` : ''} — ${s.reason} (signal ${s.id})`);
241
+ await require('./module-assess-score').printRecomposed(res.version.id); // new data re-composes the score (task 1003794)
241
242
  return 0;
242
243
  }
243
244