@bongos/core 1.19.858 → 1.19.859
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 +18 -18
- package/docs/adr/0161-publish-on-merge.md +6 -0
- package/docs/copy-inventory.md +8 -8
- package/docs/copy-registry.json +9 -9
- package/docs/module-api-changelog.md +2 -0
- package/modules/hall-ui/public/goals-page.js +4 -2
- package/modules/hall-ui/public/work.js +2 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/bump-version.js +56 -2
- package/scripts/gds/smoke-dependencies.sh +32 -2
- package/src/module-api.js +1 -1
- package/tests/bump_version.mjs +51 -14
- package/tests/hall_error_envelope.mjs +17 -0
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.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.859",
|
|
6
|
+
"core_contract": "1.19.859",
|
|
7
|
+
"source_commit": "88f0482054c54e919261f2a12807d600816ed82a",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-17T22:
|
|
9
|
+
"built_at": "2026-09-17T22:12:12.572Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 498,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2804,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "b78ad9f6f954e75b5baea41887323131be92e116c1966a2199cca319f8b0b875",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -1277,7 +1277,7 @@
|
|
|
1277
1277
|
{
|
|
1278
1278
|
"path": "docs/adr/0161-publish-on-merge.md",
|
|
1279
1279
|
"mode": "0000644",
|
|
1280
|
-
"sha256": "
|
|
1280
|
+
"sha256": "c3da608c2b3d17ceb9208abfadd8ed218654fcc67cc545528683da8a624834a0"
|
|
1281
1281
|
},
|
|
1282
1282
|
{
|
|
1283
1283
|
"path": "docs/adr/0162-review-gates-retired-rank-consistent-ci-only.md",
|
|
@@ -2062,12 +2062,12 @@
|
|
|
2062
2062
|
{
|
|
2063
2063
|
"path": "docs/copy-inventory.md",
|
|
2064
2064
|
"mode": "0000644",
|
|
2065
|
-
"sha256": "
|
|
2065
|
+
"sha256": "ae1018c0897a5358ea2c5a37aeab4a693400a5c2e3ac8e02eb8fbc805dbd0af0"
|
|
2066
2066
|
},
|
|
2067
2067
|
{
|
|
2068
2068
|
"path": "docs/copy-registry.json",
|
|
2069
2069
|
"mode": "0000644",
|
|
2070
|
-
"sha256": "
|
|
2070
|
+
"sha256": "34b45e28825cdd2cc46087b6aa96fae19931da5561275ba2df7f5121daf23d6a"
|
|
2071
2071
|
},
|
|
2072
2072
|
{
|
|
2073
2073
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2592,7 +2592,7 @@
|
|
|
2592
2592
|
{
|
|
2593
2593
|
"path": "docs/module-api-changelog.md",
|
|
2594
2594
|
"mode": "0000644",
|
|
2595
|
-
"sha256": "
|
|
2595
|
+
"sha256": "1e68c4750a4f88d910f87d06d8f99acaabe7c8c0c393a3da8b94ecd9b3b32ca8"
|
|
2596
2596
|
},
|
|
2597
2597
|
{
|
|
2598
2598
|
"path": "docs/modules-contract.md",
|
|
@@ -4952,7 +4952,7 @@
|
|
|
4952
4952
|
{
|
|
4953
4953
|
"path": "modules/hall-ui/public/goals-page.js",
|
|
4954
4954
|
"mode": "0000644",
|
|
4955
|
-
"sha256": "
|
|
4955
|
+
"sha256": "22511ab390f5b4664f6754b9c025d8949b5708b0a106e978f32aa7b49bb93938"
|
|
4956
4956
|
},
|
|
4957
4957
|
{
|
|
4958
4958
|
"path": "modules/hall-ui/public/goals-render.js",
|
|
@@ -5472,7 +5472,7 @@
|
|
|
5472
5472
|
{
|
|
5473
5473
|
"path": "modules/hall-ui/public/work.js",
|
|
5474
5474
|
"mode": "0000644",
|
|
5475
|
-
"sha256": "
|
|
5475
|
+
"sha256": "ea864a92f67de2a6d715a7372bd7b4ed5d05b90e4f6864b634b71342ed2debe8"
|
|
5476
5476
|
},
|
|
5477
5477
|
{
|
|
5478
5478
|
"path": "modules/hall-ui/public/work.states.json",
|
|
@@ -7917,12 +7917,12 @@
|
|
|
7917
7917
|
{
|
|
7918
7918
|
"path": "package-lock.json",
|
|
7919
7919
|
"mode": "0000644",
|
|
7920
|
-
"sha256": "
|
|
7920
|
+
"sha256": "2d544ea0fed5368d5c140a2e44b18b8265be912369bd47dcf78b5fcfaef6d739"
|
|
7921
7921
|
},
|
|
7922
7922
|
{
|
|
7923
7923
|
"path": "package.json",
|
|
7924
7924
|
"mode": "0000644",
|
|
7925
|
-
"sha256": "
|
|
7925
|
+
"sha256": "3aa07b12e96b6217ec805ae73ff8d535d1ac92c4c5d00d6074d8e92afd2672cb"
|
|
7926
7926
|
},
|
|
7927
7927
|
{
|
|
7928
7928
|
"path": "public-docs/index.html",
|
|
@@ -8192,7 +8192,7 @@
|
|
|
8192
8192
|
{
|
|
8193
8193
|
"path": "scripts/gds/bump-version.js",
|
|
8194
8194
|
"mode": "0000644",
|
|
8195
|
-
"sha256": "
|
|
8195
|
+
"sha256": "62c5350636e3606c577fb134150db464ddc2eb3c5ce22b063a13dae3748a500e"
|
|
8196
8196
|
},
|
|
8197
8197
|
{
|
|
8198
8198
|
"path": "scripts/gds/capture.js",
|
|
@@ -9332,7 +9332,7 @@
|
|
|
9332
9332
|
{
|
|
9333
9333
|
"path": "scripts/gds/smoke-dependencies.sh",
|
|
9334
9334
|
"mode": "0000644",
|
|
9335
|
-
"sha256": "
|
|
9335
|
+
"sha256": "de4dd849f6b4b641f33c4df0672f42c83c3012b8458c618af1c6add9dfb32734"
|
|
9336
9336
|
},
|
|
9337
9337
|
{
|
|
9338
9338
|
"path": "scripts/gds/smoke-gds.js",
|
|
@@ -9867,7 +9867,7 @@
|
|
|
9867
9867
|
{
|
|
9868
9868
|
"path": "src/module-api.js",
|
|
9869
9869
|
"mode": "0000644",
|
|
9870
|
-
"sha256": "
|
|
9870
|
+
"sha256": "6c6509130bcd722c09a1aca7f9b4f9bcd82200c2e47b9b68659d0b831ac606e5"
|
|
9871
9871
|
},
|
|
9872
9872
|
{
|
|
9873
9873
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10502,7 +10502,7 @@
|
|
|
10502
10502
|
{
|
|
10503
10503
|
"path": "tests/bump_version.mjs",
|
|
10504
10504
|
"mode": "0000644",
|
|
10505
|
-
"sha256": "
|
|
10505
|
+
"sha256": "6540646400fb4464ee823b841f908f8577d170f60c4b4928fbbfc2a3746b76d4"
|
|
10506
10506
|
},
|
|
10507
10507
|
{
|
|
10508
10508
|
"path": "tests/canonical_profile_url.mjs",
|
|
@@ -11652,7 +11652,7 @@
|
|
|
11652
11652
|
{
|
|
11653
11653
|
"path": "tests/hall_error_envelope.mjs",
|
|
11654
11654
|
"mode": "0000644",
|
|
11655
|
-
"sha256": "
|
|
11655
|
+
"sha256": "57a013b7955cdfe0edf19fcdf24dbfdfda60be625c94d2c32f258772cbd5e140"
|
|
11656
11656
|
},
|
|
11657
11657
|
{
|
|
11658
11658
|
"path": "tests/hall_kit_charts.mjs",
|
|
@@ -22,6 +22,12 @@ The consumption side (ADR 0136's subscription) was never the problem; supply was
|
|
|
22
22
|
|
|
23
23
|
1. **Every merge to `main` publishes.** A `publish` workflow fires on the `unit` check succeeding on a main push (never on a red suite), builds via `package-core` — the fail-closed no-leak gate and `--self-verify` pin check run inside the build — publishes (restricted), and tags `core-v<version>`.
|
|
24
24
|
2. **CI bumps PATCH only.** When a merge lands without a human bump, `scripts/gds/bump-version.js` bumps the patch and writes the changelog line (shape-preserving; pinned by `tests/bump_version.mjs`). A **minor or major stays a deliberate in-task human edit** — it is a statement about the doorway surface, and it decides what patch-channel subscribers receive unattended (ADR 0136). CI is not allowed to make that call.
|
|
25
|
+
|
|
26
|
+
**The promise was unkeepable until task 1003526 (2026-09-17).** A branch that hand-bumped had no commit shape the lane recognised, so `tests/bump_version.mjs`'s LIVE check failed its own PR's `unit` check by construction — that is what killed task 1003044's first ship (PR #391) — and had one merged, `publish.yml`'s record step (point 5) fires only when *CI* bumped, so the hand-cut version would have been re-packed by every later merge and **nothing new would ever have published again**. A stalled lane, not just a blocked PR. The owner chose to teach the lane the human shape rather than retire the promise.
|
|
27
|
+
|
|
28
|
+
A human release is now a first-class commit: `release: core X.Y.Z — <reason>`, matched by `HUMAN_RELEASE_COMMIT_RE` — deliberately the complement of the CI carrier's `RELEASE_COMMIT_RE`, so no subject reads as both. The two predicates now answer **different questions**, which is the correction: `isReleaseCommit` (the cascade terminator) says **no** to a human carrier, because that version is new and still needs packaging; `laneReleasedVersions` says **yes**, because the number is claimed and the lane must not publish onto it. Forcing them to agree was the defect.
|
|
29
|
+
|
|
30
|
+
The cost is one version number: declaring 1.20.0 publishes **1.20.1**, because `publish.yml` reads `taken=true`, bumps one patch past the claim, and records its own carrier — which is exactly what keeps the lane moving. Publishing the declared number *exactly* would mean teaching the record step to fire without a bump, and `.github/` is a protected surface on the lane that already minted-and-lost 1.19.716–723; the digit is not worth that edit. The minor/major signal downstream consumers actually read is preserved.
|
|
25
31
|
3. **Token custody reverses, knowingly.** A standing npm **write** Automation token (`NPM_TOKEN`) and a fine-grained **contents:write** PAT (`RELEASE_PUSH_TOKEN`, for the bump commit — the default `GITHUB_TOKEN` cannot push past the required `unit` check) live as GitHub Actions secrets. This is exactly the surface 0137 declined; the owner accepted it with the incidents as evidence. **Superseded for the npm half at task 1003202 (2026-08-25):** the write token is gone — the lane publishes via OIDC trusted publishing (ADR 0180), so no long-lived npm credential exists to steal. `RELEASE_PUSH_TOKEN` remains, as the bump commit still needs contents:write. Mitigations: the lane is **default-inert** behind the repo variable `PUBLISH_ON_MERGE=1` (an owner kill-switch symmetrical to `gating.js`), packages publish `restricted`, and the no-leak gate structurally cannot upload a leaking artifact.
|
|
26
32
|
4. **Idempotent by version-compare.** The bump commit re-triggers `unit` → `publish`, which then finds HEAD's version already on npm and no-ops. npm's duplicate-version rejection is the backstop; concurrent merges queue behind a no-cancel concurrency group.
|
|
27
33
|
5. **The bump commit is pushed only after the tarball is on the registry** (amended at task 1003914, 2026-09-13). The bump is *committed* before `package-core` runs — it stamps the version found at the ref — but the **push is the last step**, after `npm publish` returns. Originally it ran first, which made a pack or publish failure permanently lossy: `main` declared a version the registry never had, and the cascade terminator (point 4) then no-opped every following run, so only a fresh work merge could move on — bumping *past* the hole. Versions 1.19.716–723 were minted and lost exactly that way during a three-hour leak-gate fault (task 1003873). Pushing last makes the failure discard a purely local commit, and the next run retries the **same** version.
|
package/docs/copy-inventory.md
CHANGED
|
@@ -54,7 +54,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
54
54
|
| `e57ec24e13ef` | 4x | Sign in with GitHub | modules/hall-ui/public/hall-render.js:275, modules/hall-ui/public/hall-render.js:346, modules/hall-ui/public/hall-render.js:415 |
|
|
55
55
|
| `2ae36be1c531` | 4x | Start a project | modules/public-landing/public/index.html:727, modules/public-landing/public/index.html:891, modules/public-landing/public/projects.html:509 |
|
|
56
56
|
| `eff70e59d12e` | 4x | Task {…} | modules/hall-ui/public/task.js:494, modules/hall-ui/public/task.js:530, modules/hall-ui/public/task.js:959 |
|
|
57
|
-
| `b31fc908c962` | 4x | You claimed #{…}. Open a terminal to start work. | modules/hall-ui/public/goals-page.js:418, modules/hall-ui/public/goals-page.js:
|
|
57
|
+
| `b31fc908c962` | 4x | You claimed #{…}. Open a terminal to start work. | modules/hall-ui/public/goals-page.js:418, modules/hall-ui/public/goals-page.js:517, modules/hall-ui/public/work.js:904 |
|
|
58
58
|
| `1de02052abf2` | 3x | Available from the {…} rank up. | modules/hall-ui/public/gate.js:222, modules/hall-ui/public/government.js:882, modules/hall-ui/public/harbor.js:340 |
|
|
59
59
|
| `08afb1257b71` | 3x | Back to home | modules/hall-ui/public/drachmae.html:87, modules/hall-ui/public/primer.html:90, modules/hall-ui/public/primer.js:283 |
|
|
60
60
|
| `118026595c16` | 3x | Board Room | modules/hall-ui/public/board-room.html:19, modules/hall-ui/public/board-room.html:19, modules/hall-ui/public/board-room.html:31 |
|
|
@@ -65,7 +65,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
65
65
|
| `f6f68ba322be` | 3x | Open {…} | modules/hall-ui/public/goal-inbox.js:53, modules/hall-ui/public/goal-inbox.js:69, modules/hall-ui/public/goals.js:67 |
|
|
66
66
|
| `e08628967f2f` | 3x | Project settings | modules/hall-ui/public/project-settings.html:15, modules/hall-ui/public/project-settings.html:15, modules/hall-ui/public/project-settings.html:26 |
|
|
67
67
|
| `45f7bea67776` | 3x | Reading the project’s settings… | modules/public-landing/public/projects.html:791, modules/public-landing/public/projects.html:806, modules/public-landing/public/projects.html:825 |
|
|
68
|
-
| `aa4db91b5732` | 3x | Released #{…}. It returns to the queue. | modules/hall-ui/public/goals-page.js:
|
|
68
|
+
| `aa4db91b5732` | 3x | Released #{…}. It returns to the queue. | modules/hall-ui/public/goals-page.js:540, modules/hall-ui/public/work.js:945, modules/hall-ui/public/work.js:998 |
|
|
69
69
|
| `df38941b25a6` | 3x | Sign in with GitHub | modules/public-landing/public/projects.html:621, modules/public-landing/public/projects.html:693, modules/public-landing/public/projects.html:994 |
|
|
70
70
|
| `e9a366866022` | 3x | This goal is not open. | modules/hall-ui/public/goals-render.js:1279, modules/hall-ui/public/goals-render.js:1301, modules/hall-ui/public/goals-render.js:1317 |
|
|
71
71
|
| `ed394c66d49c` | 3x | What the choice changes | modules/public-landing/public/projects.html:849, modules/public-landing/public/projects.html:908, modules/public-landing/public/projects.html:920 |
|
|
@@ -487,7 +487,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
487
487
|
| `9e70797b7e97` | certain | Goal id | `modules/hall-ui/public/goals-render.js:824` |
|
|
488
488
|
| `529460e82058` | certain | Goal invitations to you | `modules/hall-ui/public/goal-inbox.js:113` |
|
|
489
489
|
| `e2a9e33abe60` | certain | Goal tasks | `modules/hall-ui/public/goals.html:136` |
|
|
490
|
-
| `e0bc28d10785` | certain | Goals could not be loaded. Refresh to try again. | `modules/hall-ui/public/goals-page.js:
|
|
490
|
+
| `e0bc28d10785` | certain | Goals could not be loaded. Refresh to try again. | `modules/hall-ui/public/goals-page.js:898` |
|
|
491
491
|
| `4517f2253d0f` | certain | Goals couldn’t be loaded just now. Refresh to try again. | `modules/hall-ui/public/goals.js:121` |
|
|
492
492
|
| `6a85997bda21` | certain | Goals created | `modules/hall-ui/public/profile.html:145` |
|
|
493
493
|
| `2ed2cb8fbffd` | certain | Goals page | `modules/hall-ui/public/goals.js:94` |
|
|
@@ -546,7 +546,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
546
546
|
| `5c2e2bcbd5fb` | certain | In Progress | `modules/hall-ui/public/work.html:95` |
|
|
547
547
|
| `75cfcdd41661` | certain | In this primer | `modules/hall-ui/public/primer.html:58` |
|
|
548
548
|
| `3102d1d90c98` | certain | Intel Mac? | `modules/hall-ui/public/settings.html:227` |
|
|
549
|
-
| `dad3388b49c9` | certain | Invitation rescinded. | `modules/hall-ui/public/goals-page.js:
|
|
549
|
+
| `dad3388b49c9` | certain | Invitation rescinded. | `modules/hall-ui/public/goals-page.js:694` |
|
|
550
550
|
| `12561be47da9` | certain | Invitation sent — they join once they accept. | `modules/hall-ui/public/goals-render.js:1261` |
|
|
551
551
|
| `24f9e88c21f6` | certain | Invite by GitHub username | `modules/hall-ui/public/watch.js:295` |
|
|
552
552
|
| `b9cb720ad5d1` | certain | Invited? Sign in | `modules/hall-ui/public/hall-render.js:286` |
|
|
@@ -821,10 +821,10 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
821
821
|
| `dba9d3f3af13` | certain | Recorded sessions | `modules/hall-ui/public/sessions.html:55` |
|
|
822
822
|
| `b40c4a61070e` | certain | Records your decision only — there is no marketplace yet, and nothing is listed anywhere. | `modules/hall-ui/public/settings.html:326` |
|
|
823
823
|
| `58af483d7a84` | certain | Release task {…} | `modules/hall-ui/public/goals-render.js:348` |
|
|
824
|
-
| `6f86e17007c6` | certain | Release your claim on #{…}? It returns to the queue and no {…} are earned. | `modules/hall-ui/public/goals-page.js:
|
|
824
|
+
| `6f86e17007c6` | certain | Release your claim on #{…}? It returns to the queue and no {…} are earned. | `modules/hall-ui/public/goals-page.js:535` |
|
|
825
825
|
| `6f86e17007c6` | certain | Release your claim on #{…}? It returns to the queue and no {…} are earned. | `modules/hall-ui/public/work.js:990` |
|
|
826
826
|
| `975ffb256651` | certain | Release {…}? {…} to the queue and no {…} are earned. | `modules/hall-ui/public/work.js:939` |
|
|
827
|
-
| `aa4db91b5732` | certain | Released #{…}. It returns to the queue. | `modules/hall-ui/public/goals-page.js:
|
|
827
|
+
| `aa4db91b5732` | certain | Released #{…}. It returns to the queue. | `modules/hall-ui/public/goals-page.js:540` |
|
|
828
828
|
| `aa4db91b5732` | certain | Released #{…}. It returns to the queue. | `modules/hall-ui/public/work.js:945` |
|
|
829
829
|
| `aa4db91b5732` | certain | Released #{…}. It returns to the queue. | `modules/hall-ui/public/work.js:998` |
|
|
830
830
|
| `c49f9b9f8864` | certain | Remake or tweak | `modules/hall-ui/public/studio.js:182` |
|
|
@@ -918,7 +918,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
918
918
|
| `9bea6404e6e1` | certain | Sign in | `modules/hall-ui/public/profile.js:208` |
|
|
919
919
|
| `9bea6404e6e1` | certain | Sign in | `modules/hall-ui/public/settings.html:42` |
|
|
920
920
|
| `2f12d46f96ca` | certain | Sign in from the app. | `modules/hall-ui/public/hall-render.js:779` |
|
|
921
|
-
| `19ab56cc3932` | certain | Sign in to filter to your goals | `modules/hall-ui/public/goals-page.js:
|
|
921
|
+
| `19ab56cc3932` | certain | Sign in to filter to your goals | `modules/hall-ui/public/goals-page.js:875` |
|
|
922
922
|
| `969f95f183ca` | certain | Sign in to the platform once to activate your profile before connecting. | `modules/hall-ui/public/profile-connections.js:220` |
|
|
923
923
|
| `b057dfbf49c5` | certain | Sign in when Claude prompts you. | `modules/hall-ui/public/hall-render.js:779` |
|
|
924
924
|
| `e57ec24e13ef` | certain | Sign in with GitHub | `modules/hall-ui/public/hall-render.js:275` |
|
|
@@ -1156,7 +1156,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1156
1156
|
| `52e93bbc07a6` | certain | You are already a member of this goal. | `modules/hall-ui/public/goals-render.js:1360` |
|
|
1157
1157
|
| `46b1265ef172` | certain | You are not a member of this goal. | `modules/hall-ui/public/goals-render.js:1316` |
|
|
1158
1158
|
| `b31fc908c962` | certain | You claimed #{…}. Open a terminal to start work. | `modules/hall-ui/public/goals-page.js:418` |
|
|
1159
|
-
| `b31fc908c962` | certain | You claimed #{…}. Open a terminal to start work. | `modules/hall-ui/public/goals-page.js:
|
|
1159
|
+
| `b31fc908c962` | certain | You claimed #{…}. Open a terminal to start work. | `modules/hall-ui/public/goals-page.js:517` |
|
|
1160
1160
|
| `b31fc908c962` | certain | You claimed #{…}. Open a terminal to start work. | `modules/hall-ui/public/work.js:904` |
|
|
1161
1161
|
| `b31fc908c962` | certain | You claimed #{…}. Open a terminal to start work. | `modules/hall-ui/public/work.js:974` |
|
|
1162
1162
|
| `bcf33947aff6` | certain | You created this task and it is already retired. | `modules/hall-ui/public/task.js:767` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
"occurrences": 4,
|
|
283
283
|
"at": [
|
|
284
284
|
"modules/hall-ui/public/goals-page.js:418",
|
|
285
|
-
"modules/hall-ui/public/goals-page.js:
|
|
285
|
+
"modules/hall-ui/public/goals-page.js:517",
|
|
286
286
|
"modules/hall-ui/public/work.js:904",
|
|
287
287
|
"modules/hall-ui/public/work.js:974"
|
|
288
288
|
]
|
|
@@ -403,7 +403,7 @@
|
|
|
403
403
|
"text": "Released #{…}. It returns to the queue.",
|
|
404
404
|
"occurrences": 3,
|
|
405
405
|
"at": [
|
|
406
|
-
"modules/hall-ui/public/goals-page.js:
|
|
406
|
+
"modules/hall-ui/public/goals-page.js:540",
|
|
407
407
|
"modules/hall-ui/public/work.js:945",
|
|
408
408
|
"modules/hall-ui/public/work.js:998"
|
|
409
409
|
]
|
|
@@ -1270,7 +1270,7 @@
|
|
|
1270
1270
|
"text": "Release your claim on #{…}? It returns to the queue and no {…} are earned.",
|
|
1271
1271
|
"occurrences": 2,
|
|
1272
1272
|
"at": [
|
|
1273
|
-
"modules/hall-ui/public/goals-page.js:
|
|
1273
|
+
"modules/hall-ui/public/goals-page.js:535",
|
|
1274
1274
|
"modules/hall-ui/public/work.js:990"
|
|
1275
1275
|
]
|
|
1276
1276
|
},
|
|
@@ -5476,7 +5476,7 @@
|
|
|
5476
5476
|
"surface": "builders-hall",
|
|
5477
5477
|
"text": "Goals could not be loaded. Refresh to try again.",
|
|
5478
5478
|
"file": "modules/hall-ui/public/goals-page.js",
|
|
5479
|
-
"line":
|
|
5479
|
+
"line": 898,
|
|
5480
5480
|
"origin": "js-text-assign",
|
|
5481
5481
|
"confidence": "certain"
|
|
5482
5482
|
},
|
|
@@ -6007,7 +6007,7 @@
|
|
|
6007
6007
|
"surface": "builders-hall",
|
|
6008
6008
|
"text": "Invitation rescinded.",
|
|
6009
6009
|
"file": "modules/hall-ui/public/goals-page.js",
|
|
6010
|
-
"line":
|
|
6010
|
+
"line": 694,
|
|
6011
6011
|
"origin": "js-notice",
|
|
6012
6012
|
"confidence": "certain"
|
|
6013
6013
|
},
|
|
@@ -8482,7 +8482,7 @@
|
|
|
8482
8482
|
"surface": "builders-hall",
|
|
8483
8483
|
"text": "Release your claim on #{…}? It returns to the queue and no {…} are earned.",
|
|
8484
8484
|
"file": "modules/hall-ui/public/goals-page.js",
|
|
8485
|
-
"line":
|
|
8485
|
+
"line": 535,
|
|
8486
8486
|
"origin": "js-notice",
|
|
8487
8487
|
"confidence": "certain"
|
|
8488
8488
|
},
|
|
@@ -8509,7 +8509,7 @@
|
|
|
8509
8509
|
"surface": "builders-hall",
|
|
8510
8510
|
"text": "Released #{…}. It returns to the queue.",
|
|
8511
8511
|
"file": "modules/hall-ui/public/goals-page.js",
|
|
8512
|
-
"line":
|
|
8512
|
+
"line": 540,
|
|
8513
8513
|
"origin": "js-notice",
|
|
8514
8514
|
"confidence": "certain"
|
|
8515
8515
|
},
|
|
@@ -9355,7 +9355,7 @@
|
|
|
9355
9355
|
"surface": "builders-hall",
|
|
9356
9356
|
"text": "Sign in to filter to your goals",
|
|
9357
9357
|
"file": "modules/hall-ui/public/goals-page.js",
|
|
9358
|
-
"line":
|
|
9358
|
+
"line": 875,
|
|
9359
9359
|
"origin": "js-text-assign",
|
|
9360
9360
|
"confidence": "certain"
|
|
9361
9361
|
},
|
|
@@ -11497,7 +11497,7 @@
|
|
|
11497
11497
|
"surface": "builders-hall",
|
|
11498
11498
|
"text": "You claimed #{…}. Open a terminal to start work.",
|
|
11499
11499
|
"file": "modules/hall-ui/public/goals-page.js",
|
|
11500
|
-
"line":
|
|
11500
|
+
"line": 517,
|
|
11501
11501
|
"origin": "js-notice",
|
|
11502
11502
|
"confidence": "certain"
|
|
11503
11503
|
},
|
|
@@ -2190,5 +2190,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2190
2190
|
landed since 1.19.856 with no explicit bump. run 35278916322. (task 1002620)
|
|
2191
2191
|
1.19.858 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2192
2192
|
landed since 1.19.857 with no explicit bump. run 35279781206. (task 1002620)
|
|
2193
|
+
1.19.859 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2194
|
+
landed since 1.19.858 with no explicit bump. run 35280770718. (task 1002620)
|
|
2193
2195
|
---------------------------------------------------------------------------
|
|
2194
2196
|
```
|
|
@@ -428,8 +428,10 @@
|
|
|
428
428
|
// or the flat legacy shape, via the same normalizers friendlyClaimError uses.
|
|
429
429
|
const det = errDetails(err.data);
|
|
430
430
|
if (err.status === 409 && errCode(err.data) === 'batch_failed') {
|
|
431
|
-
|
|
432
|
-
|
|
431
|
+
// One read covers both envelopes: errDetails returns error.details on the ADR
|
|
432
|
+
// 0116 shape and the raw body on the flat legacy one, so a second
|
|
433
|
+
// `err.data.failures` fallback here is unreachable (task 1003657).
|
|
434
|
+
const failures = Array.isArray(det.failures) ? det.failures : [];
|
|
433
435
|
const lines = failures.map((f) => `#${f.task_id} (${friendlyBatchReason(f)})`);
|
|
434
436
|
toast(lines.length
|
|
435
437
|
? `The batch could not be claimed — ${lines.join('; ')}.`
|
|
@@ -914,9 +914,9 @@
|
|
|
914
914
|
// against an object, so an all-or-nothing batch refusal rendered as the generic toast
|
|
915
915
|
// and the per-task reasons were dropped on the floor.
|
|
916
916
|
if (err.status === 409 && errCode(err.data) === 'batch_failed') {
|
|
917
|
+
// One read covers both envelopes — errDetails falls back to the body (task 1003657).
|
|
917
918
|
const bdet = errDetails(err.data);
|
|
918
|
-
const failures = Array.isArray(bdet.failures) ? bdet.failures
|
|
919
|
-
: (Array.isArray(err.data && err.data.failures) ? err.data.failures : []);
|
|
919
|
+
const failures = Array.isArray(bdet.failures) ? bdet.failures : [];
|
|
920
920
|
const lines = failures.map((f) => `#${f.task_id} (${friendlyBatchReason(f)})`);
|
|
921
921
|
toast(lines.length
|
|
922
922
|
? `The batch could not be claimed — ${lines.join('; ')}.`
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.859",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.859",
|
|
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.19.
|
|
3
|
+
"version": "1.19.859",
|
|
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",
|
|
@@ -152,16 +152,70 @@ function isReleaseCommit(subject) {
|
|
|
152
152
|
// so a failed publish left main declaring a version the registry never had, the
|
|
153
153
|
// cascade terminator no-opped every following run, and only a fresh work merge
|
|
154
154
|
// moved past it. That is how 1.19.716-723 were minted and lost (2026-09-13).
|
|
155
|
+
// HUMAN_RELEASE_COMMIT_RE — a release commit a PERSON wrote (task 1003526).
|
|
156
|
+
//
|
|
157
|
+
// ADR 0161 §2 promises "a minor or major stays a deliberate in-task human edit".
|
|
158
|
+
// The lane could not keep that promise: a branch that hand-bumped to 1.20.0 had no
|
|
159
|
+
// commit shape the lane recognised, so the LIVE test below failed its own PR's
|
|
160
|
+
// `unit` check by construction (that is what killed task 1003044's first ship,
|
|
161
|
+
// PR #391) and, had it merged, publish.yml would have packaged 1.20.0 forever
|
|
162
|
+
// without ever recording it — its record step fires only when CI itself bumped,
|
|
163
|
+
// so every later merge would re-pack the same taken version and NOTHING NEW WOULD
|
|
164
|
+
// EVER PUBLISH AGAIN. A stalled lane, not just a blocked PR.
|
|
165
|
+
//
|
|
166
|
+
// So a human release is now a first-class shape: `release: core X.Y.Z — <reason>`
|
|
167
|
+
// that is NOT this lane's own carrier phrase. Deliberately the complement of
|
|
168
|
+
// RELEASE_COMMIT_RE, so no subject can ever be read as both.
|
|
169
|
+
const HUMAN_RELEASE_COMMIT_RE = /^release: core \d+\.\d+\.\d+ \u2014 (?!CI auto-patch carrier \(publish-on-merge)\S/;
|
|
170
|
+
|
|
171
|
+
function isHumanReleaseCommit(subject) {
|
|
172
|
+
return HUMAN_RELEASE_COMMIT_RE.test(String(subject == null ? '' : subject));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// laneReleasedVersions answers "is this version SPOKEN FOR?" — which is a different
|
|
176
|
+
// question from isReleaseCommit's "did this lane already publish everything at this
|
|
177
|
+
// HEAD?", and task 1003526 is where the difference started to matter.
|
|
178
|
+
//
|
|
179
|
+
// They used to share RELEASE_COMMIT_RE, and the old comment treated that as the
|
|
180
|
+
// invariant. It is not: the two callers want OPPOSITE answers for a human release
|
|
181
|
+
// commit, and keeping them identical is exactly what made a human minor impossible.
|
|
182
|
+
//
|
|
183
|
+
// • the cascade terminator (isReleaseCommit) must say NO — a human-declared
|
|
184
|
+
// version is new and still needs publishing. Saying yes would no-op the run and
|
|
185
|
+
// the version would be bumped but never packaged (the 1.19.0 hole).
|
|
186
|
+
// • this function must say YES — the number is claimed, so the lane must not try
|
|
187
|
+
// to publish onto it. publish.yml reads that as taken=true, auto-bumps one patch
|
|
188
|
+
// past it, publishes THAT, and records its own carrier. The lane keeps moving
|
|
189
|
+
// and the human still gets their minor: 1.19.x → (declare 1.20.0) → 1.20.1.
|
|
190
|
+
//
|
|
191
|
+
// A human therefore spends a version number to change the minor/major digit. That is
|
|
192
|
+
// the whole cost of keeping this inside bump-version.js: publishing 1.20.0 EXACTLY
|
|
193
|
+
// would mean teaching publish.yml's record step to fire without a bump, and that file
|
|
194
|
+
// is a protected surface on the lane that already minted-and-lost 1.19.716-723. Not
|
|
195
|
+
// worth it for a digit.
|
|
196
|
+
//
|
|
197
|
+
// BOTH failure directions stay safe, which is what makes this acceptable here. A
|
|
198
|
+
// subject wrongly counted → the lane bumps PAST a free version (a gap, harmless). A
|
|
199
|
+
// real release missed → npm refuses the duplicate and publish.yml's already-present
|
|
200
|
+
// branch records it (task 1003914). Neither direction can double-publish.
|
|
155
201
|
function laneReleasedVersions(subjects = []) {
|
|
156
202
|
const out = new Set();
|
|
157
203
|
for (const subject of subjects) {
|
|
158
204
|
const line = String(subject == null ? '' : subject);
|
|
159
|
-
if (!RELEASE_COMMIT_RE.test(line)) continue;
|
|
205
|
+
if (!RELEASE_COMMIT_RE.test(line) && !HUMAN_RELEASE_COMMIT_RE.test(line)) continue;
|
|
160
206
|
const m = /^release: core (\d+\.\d+\.\d+) /.exec(line);
|
|
161
207
|
if (m) out.add(m[1]);
|
|
162
208
|
}
|
|
163
209
|
return out;
|
|
164
210
|
}
|
|
165
211
|
|
|
166
|
-
module.exports = {
|
|
212
|
+
module.exports = {
|
|
213
|
+
bumpPatch,
|
|
214
|
+
CONST_RE,
|
|
215
|
+
RELEASE_COMMIT_RE,
|
|
216
|
+
HUMAN_RELEASE_COMMIT_RE,
|
|
217
|
+
isReleaseCommit,
|
|
218
|
+
isHumanReleaseCommit,
|
|
219
|
+
laneReleasedVersions,
|
|
220
|
+
};
|
|
167
221
|
if (require.main === module) main();
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# 7. Claim B, ship B (active → completed → confirmed → shipped)
|
|
13
13
|
# 8. Verify A auto-promoted backlog→ready (or stays ready if step 5 ran)
|
|
14
14
|
# 9. Claim A — succeeds
|
|
15
|
-
# 10. Release A
|
|
15
|
+
# 10. Release A, abandon A (B is shipped and cannot be abandoned)
|
|
16
16
|
#
|
|
17
17
|
# Run from any environment with a valid CLI session (/builder-setup).
|
|
18
18
|
# Requires curl.
|
|
@@ -77,8 +77,38 @@ echo " A status: $A_STATUS"
|
|
|
77
77
|
echo "=== 8. Claim A — must succeed now ==="
|
|
78
78
|
node scripts/gds/claim.js "$A_ID" --worktree "smoke-$SUFFIX-A"
|
|
79
79
|
|
|
80
|
-
echo "=== 9. Cleanup
|
|
80
|
+
echo "=== 9. Cleanup — abandon A; B is shipped and stays ==="
|
|
81
|
+
# task 1004026: this step used to ANNOUNCE "release A; mark both abandoned" and then
|
|
82
|
+
# only release A. Neither task reached a terminal state, so every run leaked two
|
|
83
|
+
# __smoke__ rows into the live tasks table — invisibly, because anyone grepping the
|
|
84
|
+
# cleanup step read a line saying both were handled.
|
|
85
|
+
#
|
|
86
|
+
# "mark both abandoned" was never possible. B is SHIPPED by step 6, and the abandon
|
|
87
|
+
# route refuses shipped work (cannot_abandon_shipped) because shipped rows are
|
|
88
|
+
# immutable history. Only A can reach a terminal state here, so the echo now states
|
|
89
|
+
# what the code does instead of the reverse.
|
|
90
|
+
#
|
|
91
|
+
# Follows scripts/gds/smoke-write.sh's cleanup (task 1002018): abandon is the right
|
|
92
|
+
# terminal state for a smoke row, and cleanup is STRICTLY best-effort. task.abandon is
|
|
93
|
+
# floor-metic (ADR 0152), so a Xenos/Thetes token gets a 403 here while every assertion
|
|
94
|
+
# above genuinely passed — a cleanup that cannot run must never turn a passing smoke
|
|
95
|
+
# into a failing one. Hence the `|| true` and the reported-not-raised status codes.
|
|
96
|
+
# Reaching this line at all means every assertion passed: the script is `set -e` and
|
|
97
|
+
# each check above exits non-zero on failure, so a FAILED run stops earlier and leaves
|
|
98
|
+
# both rows in place for inspection, which is the same deliberate choice smoke-write makes.
|
|
81
99
|
node scripts/gds/release.js "$A_ID" --reason "smoke cleanup" || true
|
|
82
100
|
|
|
101
|
+
A_CLEANUP_CODE=$(curl -sS -o /dev/null -w '%{http_code}' -X POST \
|
|
102
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
103
|
+
--data '{"reason":"smoke cleanup (task 1004026) - dependency smoke passed; the throwaway row has served its purpose"}' \
|
|
104
|
+
"$BASE/api/bongos/tasks/$A_ID/abandon") || true
|
|
105
|
+
case "${A_CLEANUP_CODE:-000}" in
|
|
106
|
+
2*) echo " PASS cleaned up throwaway task #$A_ID (abandoned)" ;;
|
|
107
|
+
403) echo " SKIP cleanup — task.abandon needs Metic+ (ADR 0152); task #$A_ID left in the ledger" ;;
|
|
108
|
+
000) echo " SKIP cleanup — POST /tasks/$A_ID/abandon got no response; task #$A_ID left in the ledger" ;;
|
|
109
|
+
*) echo " SKIP cleanup — POST /tasks/$A_ID/abandon returned HTTP $A_CLEANUP_CODE; task #$A_ID left in the ledger" ;;
|
|
110
|
+
esac
|
|
111
|
+
echo " NOTE task #$B_ID is SHIPPED and is deliberately left in the ledger — the abandon route refuses shipped work (cannot_abandon_shipped)."
|
|
112
|
+
|
|
83
113
|
echo
|
|
84
114
|
echo "ALL SMOKE STEPS PASSED."
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.859'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
package/tests/bump_version.mjs
CHANGED
|
@@ -276,14 +276,21 @@ test('laneReleasedVersions reads the versions this lane announced', () => {
|
|
|
276
276
|
assert.equal(v.has('1.19.369'), false, 'a version never announced must read as free');
|
|
277
277
|
});
|
|
278
278
|
|
|
279
|
-
test('a HUMAN release commit
|
|
280
|
-
//
|
|
281
|
-
//
|
|
279
|
+
test('a HUMAN release commit IS counted — the lane bumps past it rather than onto it', () => {
|
|
280
|
+
// REVERSED by task 1003526. This test used to assert the opposite, reasoning that
|
|
281
|
+
// "counting it here would skip the publish of a hand-cut release". The skip is real
|
|
282
|
+
// but it is not a loss: publish.yml reads taken=true, bumps ONE PATCH past the
|
|
283
|
+
// declared number, publishes that, and records its own carrier. The human's minor
|
|
284
|
+
// ships as 1.20.1 and the lane keeps moving.
|
|
285
|
+
//
|
|
286
|
+
// Not counting it is what actually lost releases. publish.yml's record step fires
|
|
287
|
+
// only when CI itself bumped, so a published-but-unrecorded 1.20.0 would be re-packed
|
|
288
|
+
// by every later merge and nothing new would ever reach the registry again.
|
|
282
289
|
const v = bump.laneReleasedVersions([
|
|
283
290
|
'release: core 1.19.2 — carrier for the init-blocker fixes',
|
|
284
291
|
'release: core 1.20.0 — hand-cut minor',
|
|
285
292
|
]);
|
|
286
|
-
assert.
|
|
293
|
+
assert.deepEqual([...v].sort(), ['1.19.2', '1.20.0']);
|
|
287
294
|
});
|
|
288
295
|
|
|
289
296
|
test('malformed and empty input yields an empty set, never a throw', () => {
|
|
@@ -295,19 +302,49 @@ test('malformed and empty input yields an empty set, never a throw', () => {
|
|
|
295
302
|
assert.equal(bump.laneReleasedVersions([null, undefined, '', 42]).size, 0);
|
|
296
303
|
});
|
|
297
304
|
|
|
298
|
-
test('
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
305
|
+
test('a human release commit is SPOKEN FOR but does not terminate the cascade', () => {
|
|
306
|
+
// task 1003526. These two predicates used to share RELEASE_COMMIT_RE, and the old
|
|
307
|
+
// test asserted they must always agree. That assertion was the bug: the two callers
|
|
308
|
+
// need OPPOSITE answers for a human release, and forcing them to agree is precisely
|
|
309
|
+
// what made ADR 0161 §2's promised minor/major impossible to land.
|
|
310
|
+
const human = 'release: core 1.20.0 — minor: new doorway export (task 1003526)';
|
|
311
|
+
|
|
312
|
+
// NO: it is not this lane's own carrier, so publish.yml must NOT no-op — the
|
|
313
|
+
// version is new and still has to be packaged. Saying yes here is the 1.19.0 hole.
|
|
314
|
+
assert.equal(bump.isReleaseCommit(human), false);
|
|
315
|
+
assert.equal(bump.isHumanReleaseCommit(human), true);
|
|
316
|
+
|
|
317
|
+
// YES: the number is claimed, so the lane must not publish onto it. publish.yml
|
|
318
|
+
// reads taken=true, bumps one patch past it, and records its own carrier — which
|
|
319
|
+
// is what keeps the lane moving instead of re-packing a taken version forever.
|
|
320
|
+
assert.equal(bump.laneReleasedVersions([human]).has('1.20.0'), true);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test('the CI carrier still both terminates the cascade and counts as released', () => {
|
|
324
|
+
const ci = 'release: core 1.19.368 — CI auto-patch carrier (publish-on-merge, ADR 0161)';
|
|
325
|
+
assert.equal(bump.isReleaseCommit(ci), true);
|
|
326
|
+
assert.equal(bump.isHumanReleaseCommit(ci), false, 'the two shapes must never both match');
|
|
327
|
+
assert.equal(bump.laneReleasedVersions([ci]).has('1.19.368'), true);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('an ordinary commit is neither shape', () => {
|
|
331
|
+
const no = 'chore: not a release at all';
|
|
332
|
+
assert.equal(bump.isReleaseCommit(no), false);
|
|
333
|
+
assert.equal(bump.isHumanReleaseCommit(no), false);
|
|
334
|
+
assert.equal(bump.laneReleasedVersions([no]).size, 0);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test('a hand-bumped branch passes the LIVE check its own PR runs', () => {
|
|
338
|
+
// The regression that killed task 1003044's first ship (PR #391): the branch bumped
|
|
339
|
+
// CORE_VERSION to a minor, no commit shape declared it, and the LIVE test below
|
|
340
|
+
// failed the PR's own `unit` check by construction. With the human carrier in the
|
|
341
|
+
// branch's log the same check now passes.
|
|
302
342
|
const subjects = [
|
|
343
|
+
'release: core 1.20.0 — minor: new doorway export (task 1003526)',
|
|
344
|
+
'feat: the doorway export itself',
|
|
303
345
|
'release: core 1.19.368 — CI auto-patch carrier (publish-on-merge, ADR 0161)',
|
|
304
|
-
'release: core 1.19.2 — carrier for the init-blocker fixes',
|
|
305
|
-
'chore: not a release at all',
|
|
306
346
|
];
|
|
307
|
-
|
|
308
|
-
const counted = bump.laneReleasedVersions([s]).size === 1;
|
|
309
|
-
assert.equal(counted, bump.isReleaseCommit(s), `disagreement on: ${s}`);
|
|
310
|
-
}
|
|
347
|
+
assert.equal(bump.laneReleasedVersions(subjects).has('1.20.0'), true);
|
|
311
348
|
});
|
|
312
349
|
|
|
313
350
|
test('LIVE: the version HEAD declares is one this lane already released', () => {
|
|
@@ -108,6 +108,23 @@ await t('errDetails takes error.details, else falls back to the BODY (flat shape
|
|
|
108
108
|
assert.deepEqual(errDetails({ error: 'c', conflicts: [{ title: 'B' }] }).conflicts, [{ title: 'B' }]);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
await t('one errDetails read covers batch failures on BOTH shapes (task 1003657)', () => {
|
|
112
|
+
const { errDetails } = loadOTB();
|
|
113
|
+
const failures = [{ task_id: 7, reason: 'ALREADY_CLAIMED' }];
|
|
114
|
+
// This is the assertion that makes the second fallback deletable. work.js and
|
|
115
|
+
// goals-page.js used to read `det.failures` and THEN `err.data.failures`; the
|
|
116
|
+
// second branch can never run, because errDetails returns error.details on the
|
|
117
|
+
// ADR 0116 shape and the raw BODY on the flat legacy one — so `.failures` is
|
|
118
|
+
// reachable through one read either way. If a future errDetails stops falling
|
|
119
|
+
// back to the body, this fails and the callers need their fallback back.
|
|
120
|
+
assert.deepEqual(errDetails({ error: { code: 'batch_failed', details: { failures } } }).failures, failures);
|
|
121
|
+
assert.deepEqual(errDetails({ error: 'batch_failed', failures }).failures, failures);
|
|
122
|
+
// And the shape that would have made the fallback reachable — nested details
|
|
123
|
+
// alongside a top-level failures list — is not one the server can emit:
|
|
124
|
+
// src/bongos/api-errors.js envelope() puts nothing but `error` at the top level.
|
|
125
|
+
assert.equal(errDetails({ error: { code: 'batch_failed', details: {} } }).failures, undefined);
|
|
126
|
+
});
|
|
127
|
+
|
|
111
128
|
await t('the readers survive hostile / empty input without throwing', () => {
|
|
112
129
|
const { errCode, errMessage, errDetails } = loadOTB();
|
|
113
130
|
for (const bad of [undefined, null, {}, { error: null }, { error: 0 }, { error: [] }, 'str', 42]) {
|