@bongos/core 1.19.353 → 1.19.355

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,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.353",
6
- "core_contract": "1.19.353",
7
- "source_commit": "5bb1f8185d48f3d3d53181f4525eca45b0cef665",
5
+ "core_version": "1.19.355",
6
+ "core_contract": "1.19.355",
7
+ "source_commit": "a7ad49c28f305814b88df556ae4c1d18ceca1a01",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-25T13:07:06.857Z",
9
+ "built_at": "2026-08-25T13:24:07.447Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 329,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 1857,
20
- "tree_sha256": "3b39dee80eea8539fc0a7b82684369a69c58b09c426cac168f029815bc78270e",
20
+ "tree_sha256": "abdcd03b753d6da9681bddd073feee645787426d01b5d8ecd460cba64d4a6b73",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -367,7 +367,7 @@
367
367
  {
368
368
  "path": "clients/bongos-client/index.d.ts",
369
369
  "mode": "0000644",
370
- "sha256": "8a03a6a6fa27ca367cef614e2d03bdf8c2363b50e5a11eca3b9e6faa803080f7"
370
+ "sha256": "f32214ef80ab2e05d032e35da07b84e7300a490001dd39a7f7d0ff1997053836"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/index.mjs",
@@ -1452,7 +1452,7 @@
1452
1452
  {
1453
1453
  "path": "docs/api/openapi.json",
1454
1454
  "mode": "0000644",
1455
- "sha256": "86c346871a6181f8396b8daa5dcaa59180109a414162389786a23a43b51b93d6"
1455
+ "sha256": "03a8b40f27b4ad5bd8219d4a755eb18c7b925feee465c6d97d3cb1b8c372651f"
1456
1456
  },
1457
1457
  {
1458
1458
  "path": "docs/architecture.md",
@@ -4477,7 +4477,7 @@
4477
4477
  {
4478
4478
  "path": "modules/provisioning/provisioning.js",
4479
4479
  "mode": "0000644",
4480
- "sha256": "862fa78c7272a28cdc644debfd8ec364b80b635e8b9a6f41afb76b93312f27dd"
4480
+ "sha256": "ff156c4c0252240026a5ce98547efa76d585d6f0fd88c5b0b95c5598901865ab"
4481
4481
  },
4482
4482
  {
4483
4483
  "path": "modules/provisioning/rate-limit.js",
@@ -4487,7 +4487,7 @@
4487
4487
  {
4488
4488
  "path": "modules/provisioning/routes/provisioning.js",
4489
4489
  "mode": "0000644",
4490
- "sha256": "5e9b3d225f06ab2d92b1f85d0d338ae6fa9aaae31afad92b043172e048455895"
4490
+ "sha256": "026234f2c2c212a7ecc3808380bd3ea0cca81e2efc39c619968c505099830e5c"
4491
4491
  },
4492
4492
  {
4493
4493
  "path": "modules/provisioning/tests/liveness.mjs",
@@ -4787,12 +4787,12 @@
4787
4787
  {
4788
4788
  "path": "package-lock.json",
4789
4789
  "mode": "0000644",
4790
- "sha256": "0b1bb5323c63aefbe9f58e5bd5eba8cfed791c5089bf5dbae18fde4055c31299"
4790
+ "sha256": "2e354a8f810ac30ec70aab86c458d275f4d598788d8dbbfb1fc2a91a9f035ff1"
4791
4791
  },
4792
4792
  {
4793
4793
  "path": "package.json",
4794
4794
  "mode": "0000644",
4795
- "sha256": "c524de81eaba481839a9515c321c48d231506f677459d76c495bb51ebfd8b90c"
4795
+ "sha256": "7dc6f776203244cb6e6b909f1a32c93948d04dc243bfd714d281bf1b8ee8fcdb"
4796
4796
  },
4797
4797
  {
4798
4798
  "path": "public-docs/index.html",
@@ -5052,7 +5052,7 @@
5052
5052
  {
5053
5053
  "path": "public-landing/projects.html",
5054
5054
  "mode": "0000644",
5055
- "sha256": "6d57b80519977cc23b3da231164e20b645ced2b6bbf97ebd3e64f3f9b393321b"
5055
+ "sha256": "42ddc3ecf96a31919f0e700f2cd0092d8225858c78ef4d231e4b3ac301b5b318"
5056
5056
  },
5057
5057
  {
5058
5058
  "path": "public-landing/world/assets/clouds/cloud-island-large.png",
@@ -6617,7 +6617,7 @@
6617
6617
  {
6618
6618
  "path": "src/bongos/serve-internal.js",
6619
6619
  "mode": "0000644",
6620
- "sha256": "bf37dbda6a10fe8b21f6df01e8bdd62aea3f539523464b37666ffd535ceb7e00"
6620
+ "sha256": "025676342224c2944fa2361965c12d9e6cf812fd17541c737a32fab7544c2709"
6621
6621
  },
6622
6622
  {
6623
6623
  "path": "src/bongos/stealth-gate.js",
@@ -6652,7 +6652,7 @@
6652
6652
  {
6653
6653
  "path": "src/module-api.js",
6654
6654
  "mode": "0000644",
6655
- "sha256": "82bd181f16c9ee484e55c879439a7f61ff056588080a57bd95a3881d89b726f3"
6655
+ "sha256": "43ca06d2e5757257056bcaac608518df57c750d552ad667ec751a6ca28a0c00a"
6656
6656
  },
6657
6657
  {
6658
6658
  "path": "src/module-loader/catalog.js",
@@ -8147,7 +8147,7 @@
8147
8147
  {
8148
8148
  "path": "tests/landing_page.mjs",
8149
8149
  "mode": "0000644",
8150
- "sha256": "2efddbab276f2ef38dbcf09ef6b76d4c1ff58f68c8b11a8803c7a27b605b385f"
8150
+ "sha256": "7457d53dee7cce5770c17ec908c0f051e72092d2fa1cf5a9a1198fbdac64145a"
8151
8151
  },
8152
8152
  {
8153
8153
  "path": "tests/lib_sh_resolution.mjs",
@@ -8542,7 +8542,7 @@
8542
8542
  {
8543
8543
  "path": "tests/projects_hub_pre_uat.mjs",
8544
8544
  "mode": "0000644",
8545
- "sha256": "4f8b786e8704b418354d2551d20466e4d9ca705ca7ac39d00cd2dc83e3080032"
8545
+ "sha256": "919caac313f78c8c88e7ecca1a49ff2f1da53e443acda434f0648a9b5215f24d"
8546
8546
  },
8547
8547
  {
8548
8548
  "path": "tests/promote_goal_id.mjs",
@@ -8582,7 +8582,7 @@
8582
8582
  {
8583
8583
  "path": "tests/provisioning_settings.mjs",
8584
8584
  "mode": "0000644",
8585
- "sha256": "a525fdcfa2fde8edd2be3198ca7213b9b6bc43a12f748a718a570b7f993972b6"
8585
+ "sha256": "7b6aa958f626054746e5272113bb314a118073507d5baed65f52cafdc25f7085"
8586
8586
  },
8587
8587
  {
8588
8588
  "path": "tests/provisioning_settings_env.mjs",
@@ -81,7 +81,7 @@ export interface GetProjectsResponse { projects: unknown }
81
81
  export interface GetProvisioningFleetResponse { instances: unknown }
82
82
  export interface GetProvisioningGithubAppStatusResponse { ok: boolean; status: unknown; ready: unknown; terminal: unknown; domain: unknown; instance_status: unknown; app_slug: unknown }
83
83
  export interface GetProvisioningHealthResponse { module: unknown; ok: boolean; coreVersion: unknown }
84
- export interface GetProvisioningInstancesIdResponse { instance: unknown; open_intent: unknown }
84
+ export interface GetProvisioningInstancesIdResponse { instance: unknown; open_intent: unknown; github_app: unknown }
85
85
  export interface GetProvisioningInstancesIdSettingsResponse { ok: boolean; settings: unknown; options: unknown }
86
86
  export interface GetProvisioningInstancesResponse { instances: unknown }
87
87
  export interface GetProvisioningOnboardPlanResponse { mode: unknown; steps: unknown }
@@ -14994,11 +14994,13 @@
14994
14994
  "type": "object",
14995
14995
  "properties": {
14996
14996
  "instance": {},
14997
- "open_intent": {}
14997
+ "open_intent": {},
14998
+ "github_app": {}
14998
14999
  },
14999
15000
  "required": [
15000
15001
  "instance",
15001
- "open_intent"
15002
+ "open_intent",
15003
+ "github_app"
15002
15004
  ]
15003
15005
  },
15004
15006
  "GetProvisioningInstancesIdSettingsResponse": {
@@ -232,6 +232,18 @@ function publicInstance(row) {
232
232
  };
233
233
  }
234
234
 
235
+ // The GitHub-App manifest leg's truth for an instance, as the read surface carries
236
+ // it (task 1003235): the latest attempt's lifecycle status + the App's public slug.
237
+ // Same vocabulary as GET /github-app/status ('pending' | 'code_received' |
238
+ // 'converting' | 'done' | 'error' | 'expired'), so the wizard can seed its
239
+ // `live.manifest` from a plain instance read after a reload, a second tab, or
240
+ // another device — no sessionStorage bridge needed. null = no attempt ever made.
241
+ // PURE: an allow-list projection of the manifest row, never the row itself.
242
+ function publicGithubApp(manifestRow) {
243
+ if (!manifestRow || !manifestRow.status) return null;
244
+ return { status: String(manifestRow.status), app_slug: manifestRow.app_slug || null };
245
+ }
246
+
235
247
  // The instance's EFFECTIVE settings: the defaults overlaid with the stored,
236
248
  // on-vocabulary keys. An off-vocabulary or unknown stored value falls back to
237
249
  // its default rather than leaking into the read surface. PURE.
@@ -812,7 +824,7 @@ module.exports = {
812
824
  isValidSlug, costEstimateUsd, publicInstance, normalizeHostname,
813
825
  defaultDomainForSlug, isReservedHostname, effectiveSettings,
814
826
  // pure — GitHub App Manifest flow (task 2080)
815
- githubAppName, buildGithubAppManifest, manifestPostUrl,
827
+ githubAppName, buildGithubAppManifest, manifestPostUrl, publicGithubApp,
816
828
  // data access
817
829
  isProvisionedHostname,
818
830
  getInstanceById, getInstanceBySlug, getInstanceByDomain, listInstancesForOwner, listAllInstances,
@@ -619,9 +619,13 @@ module.exports = function provisioningRoutes() {
619
619
  return res.fail('instance_not_found', 404);
620
620
  }
621
621
  const open = await provisioning.getOpenIntent(pool, id);
622
+ // The GitHub-App leg's truth rides the same read (task 1003235), so the done
623
+ // panel recovers it from server state after a reload — not from sessionStorage.
624
+ const manifest = await provisioning.getLatestOAuthManifestForInstance(pool, id);
622
625
  res.json({
623
626
  instance: provisioning.publicInstance(inst),
624
627
  open_intent: open ? { action: open.action, state: open.state } : null,
628
+ github_app: provisioning.publicGithubApp(manifest),
625
629
  });
626
630
  } catch (err) {
627
631
  log.error('[provisioning] GET /provisioning/instances/:id', err);
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.353",
3
+ "version": "1.19.355",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.353",
9
+ "version": "1.19.355",
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.353",
3
+ "version": "1.19.355",
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",
@@ -3555,6 +3555,18 @@ summary{min-height:24px;padding:3px 0;}
3555
3555
  var inst = data.instance;
3556
3556
  if (inst) inst.open_intent = data.open_intent || null; /* F22: the strip reads intents */
3557
3557
  if (inst) watchFlow = inst.torn_down_at ? 'revive' : 'standup';
3558
+ /* server-derived manifest truth (task 1003235): a reload, a second tab
3559
+ or another device re-learns the GitHub-App leg from this same read.
3560
+ A live manifest poll owns live.manifest while it runs, so the seed
3561
+ yields to it. */
3562
+ var ga = data.github_app;
3563
+ if (ga && ga.status && !manifestPollTimer) {
3564
+ var seeded = ga.status === 'done' ? 'done' : ga.status;
3565
+ var seedChanged = seeded !== live.manifest || (!!ga.app_slug && ga.app_slug !== live.appSlug);
3566
+ if (ga.app_slug) live.appSlug = ga.app_slug;
3567
+ live.manifest = seeded;
3568
+ if (seedChanged) { rememberManifest(undefined, live.manifest, live.appSlug || undefined); renderSteps(); }
3569
+ }
3558
3570
  /* the checklist reflects live state (task 1002694): a status transition —
3559
3571
  e.g. the scaffold landing — re-renders the steps (change-only, so the
3560
3572
  5s tick never clobbers an open dropdown or mid-flight button) */
@@ -169,7 +169,8 @@ function applyBrandTokens(html, brand = clientBranding(), origin = safePublicOri
169
169
  const tagline = (brand.copy && brand.copy.tagline) || '';
170
170
  const cur = (brand.currency && brand.currency.label) || 'credits';
171
171
  const Cur = cur ? cur.charAt(0).toUpperCase() + cur.slice(1) : cur;
172
- return String(html == null ? '' : html)
172
+ const hall = hallOrigin || origin || '';
173
+ return dropEmptyHrefLinks(String(html == null ? '' : html), { publicOrigin: origin || '', buildersOrigin: hall, sourceRepoUrl: sourceRepo || '' })
173
174
  .split('{{worldName}}').join(esc(world))
174
175
  .split('{{productName}}').join(esc(product))
175
176
  .split('{{Currency}}').join(esc(Cur))
@@ -178,10 +179,23 @@ function applyBrandTokens(html, brand = clientBranding(), origin = safePublicOri
178
179
  .split('{{publicOrigin}}').join(esc(origin || ''))
179
180
  // a pack that names no hall of its own resolves to its OWN apex — never to
180
181
  // whichever instance authored the file
181
- .split('{{buildersOrigin}}').join(esc(hallOrigin || origin || ''))
182
+ .split('{{buildersOrigin}}').join(esc(hall))
182
183
  .split('{{sourceRepoUrl}}').join(esc(sourceRepo || ''))
183
184
  .split('{{instanceBase}}').join(esc(instanceBase || ''));
184
185
  }
186
+ // A link whose href is a BARE origin token that resolves empty is dropped whole,
187
+ // server-side (task 1003242; the branding contract): a pack that names no domains
188
+ // would otherwise stamp `href=""` — a dead hall pill on every page carrying one,
189
+ // and only index.html scrubs those client-side. Exact-token hrefs only: a token
190
+ // inside a longer URL still stamps (an empty prefix leaves a relative path).
191
+ function dropEmptyHrefLinks(html, values) {
192
+ let out = html;
193
+ for (const [token, value] of Object.entries(values)) {
194
+ if (value) continue;
195
+ out = out.replace(new RegExp(`<a\\b[^>]*\\bhref="\\{\\{${token}\\}\\}"[^>]*>[\\s\\S]*?<\\/a>`, 'g'), '');
196
+ }
197
+ return out;
198
+ }
185
199
  // Every token lands in HTML — as element text, or inside a double-quoted
186
200
  // attribute (href/content). Escaping is defence in depth, not a live fix: the
187
201
  // only source is config/branding.json, which is committed, code-reviewed and
package/src/module-api.js CHANGED
@@ -1136,8 +1136,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
1136
1136
  // landed since 1.19.351 with no explicit bump. run 32850767673. (task 1002620)
1137
1137
  // 1.19.353 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1138
1138
  // landed since 1.19.352 with no explicit bump. run 32851392269. (task 1002620)
1139
+ // 1.19.354 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1140
+ // landed since 1.19.353 with no explicit bump. run 32852045058. (task 1002620)
1141
+ // 1.19.355 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1142
+ // landed since 1.19.354 with no explicit bump. run 32853063015. (task 1002620)
1139
1143
  // ---------------------------------------------------------------------------
1140
- const CORE_VERSION = '1.19.353'; // CI auto-patch carrier (ADR 0161); see changelog above
1144
+ const CORE_VERSION = '1.19.355'; // CI auto-patch carrier (ADR 0161); see changelog above
1141
1145
 
1142
1146
  // A namespaced logger so a module's log lines are attributable + consistent.
1143
1147
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -142,6 +142,24 @@ test('an unstamped link is removed, not left dangling', () => {
142
142
  assert.ok(out.length > 0);
143
143
  });
144
144
 
145
+ test('a pack with NO domains drops the hall pill server-side rather than stamping href="" (task 1003242)', () => {
146
+ // the hub has no client scrubber, so an empty token must never reach it as a dead link
147
+ const HUB = fs.readFileSync(path.join(ROOT, 'public-landing', 'projects.html'), 'utf8');
148
+ assert.match(HUB, /data-link-hall href="\{\{buildersOrigin\}\}"/, 'the hub pill is token-stamped');
149
+ const none = applyBrandTokens(HUB, BRAND, '', '');
150
+ assert.doesNotMatch(none, /href=""/, 'no empty href survives the stamp');
151
+ assert.doesNotMatch(none, /data-link-hall/, 'the pill element is omitted whole, not left dead');
152
+ assert.doesNotMatch(none, /\{\{[a-zA-Z]+\}\}/, 'every other token still stamps');
153
+ const apexOnly = applyBrandTokens(HUB, BRAND, 'https://spike-harbor.example', '');
154
+ assert.match(apexOnly, /data-link-hall href="https:\/\/spike-harbor\.example"/, 'an apex alone keeps the pill, pointed at the apex');
155
+ const both = applyBrandTokens(HUB, BRAND, 'https://spike-harbor.example', 'https://builders.spike-harbor.example');
156
+ assert.match(both, /data-link-hall href="https:\/\/builders\.spike-harbor\.example"/);
157
+ // the landing page too — its client-side scrubber is no longer the only guard
158
+ assert.doesNotMatch(applyBrandTokens(HTML, BRAND, '', ''), /<a\b[^>]*href=""/);
159
+ // a token INSIDE a longer href is a relative path once stamped empty, not a dead link — left alone
160
+ assert.equal(applyBrandTokens('<a href="{{publicOrigin}}/docs">Docs</a>', BRAND, '', ''), '<a href="/docs">Docs</a>');
161
+ });
162
+
145
163
  // ── the branding cascade + portability ─────────────────────────────────────
146
164
 
147
165
  test('the page declares no :root — a page-local one defeats re-branding (C1)', () => {
@@ -484,3 +484,17 @@ test('control nits: orb cursor, caret under reduced motion, mode label, home lab
484
484
  assert.match(HUB, /\.again\{[^}]*padding:6px 2px;min-height:24px;/);
485
485
  assert.match(HUB, /\nsummary\{min-height:24px;padding:3px 0;\}/, 'every fold is a 24px target; the disclosure marker stays');
486
486
  });
487
+
488
+ /* ── server-derived manifest truth (task 1003235) ── */
489
+ test('the done panel re-learns the GitHub-App leg from the instance read, yielding to a live manifest poll', () => {
490
+ /* the seed lives in startProgress's nested tick(), past where fn() stops — read the script */
491
+ const sp = SCRIPT.slice(SCRIPT.indexOf('function startProgress('));
492
+ assert.match(sp, /var ga = data\.github_app;\n\s*if \(ga && ga\.status && !manifestPollTimer\) \{/, 'seeded from the same 5s read; a running manifest poll owns live.manifest');
493
+ assert.match(sp, /var seeded = ga\.status === 'done' \? 'done' : ga\.status;/, 'the status route’s vocabulary, verbatim');
494
+ assert.match(sp, /if \(ga\.app_slug\) live\.appSlug = ga\.app_slug;\n\s*live\.manifest = seeded;/);
495
+ assert.match(sp, /if \(seedChanged\) \{ rememberManifest\(undefined, live\.manifest, live\.appSlug \|\| undefined\); renderSteps\(\); \}/, 'change-only: an identical tick neither rewrites the bridge nor re-renders');
496
+ const seedAt = sp.indexOf('var ga = data.github_app;');
497
+ const statusAt = sp.indexOf("if (inst && inst.status !== live.instStatus)");
498
+ assert.ok(seedAt > 0 && seedAt < statusAt, 'the manifest seed lands before the status re-render, so one renderSteps() paints both');
499
+ assert.match(fn('enter'), /if \(created\.manifest\) \{ live\.manifest = created\.manifest; live\.appSlug = created\.app_slug \|\| null; \}/, 'the sessionStorage bridge stays as the pre-first-tick seed');
500
+ });
@@ -42,6 +42,8 @@ provisioning.updateInstanceSettings = async (_db, id, patch) => {
42
42
  };
43
43
  provisioning.recordEvent = async (_db, e) => { events.push(e); };
44
44
  provisioning.getOpenIntent = async () => null;
45
+ let manifest = null; // the latest manifest attempt the read surfaces (task 1003235)
46
+ provisioning.getLatestOAuthManifestForInstance = async () => manifest;
45
47
 
46
48
  const api = require('../src/module-api.js');
47
49
  let builder = { id: 7, github_login: 'owner', rank: 'thetes' };
@@ -106,6 +108,31 @@ await ta('owner reads their own instance', async () => {
106
108
  assert.equal(r.body.instance.slug, 'spike');
107
109
  });
108
110
 
111
+ await ta('the read carries the GitHub-App leg\'s truth — github_app {status, app_slug} from the latest manifest attempt (task 1003235)', async () => {
112
+ reset();
113
+ manifest = { id: 3, instance_id: 18, status: 'done', app_slug: 'spike-bongos', github_code: 'never-surfaced', state: 'never-surfaced' };
114
+ const r = await get('/provisioning/instances/18');
115
+ assert.equal(r.status, 200, r.raw);
116
+ assert.deepEqual(r.body.github_app, { status: 'done', app_slug: 'spike-bongos' }, 'an allow-list projection — the code and the state token never ride the read');
117
+ assert.equal(r.body.instance.slug, 'spike', 'the instance projection is untouched');
118
+ });
119
+
120
+ await ta('no manifest attempt yet → github_app is null, not absent (a reload can tell "never started" from "unknown")', async () => {
121
+ reset();
122
+ manifest = null;
123
+ const r = await get('/provisioning/instances/18');
124
+ assert.equal(r.status, 200, r.raw);
125
+ assert.ok('github_app' in r.body, 'the key is always present');
126
+ assert.equal(r.body.github_app, null);
127
+ });
128
+
129
+ await ta('publicGithubApp is a pure allow-list projection with the status route\'s vocabulary', async () => {
130
+ assert.equal(provisioning.publicGithubApp(null), null);
131
+ assert.equal(provisioning.publicGithubApp({ app_slug: 'x' }), null, 'a row with no status is no truth');
132
+ assert.deepEqual(provisioning.publicGithubApp({ status: 'pending', github_code: 'secret' }), { status: 'pending', app_slug: null });
133
+ assert.deepEqual(provisioning.publicGithubApp({ status: 'code_received', app_slug: 'mercury-bongos' }), { status: 'code_received', app_slug: 'mercury-bongos' });
134
+ });
135
+
109
136
  await ta('ANOTHER builder\'s GET → 404 (no existence leak)', async () => {
110
137
  reset({ as: { id: 8, github_login: 'stranger', rank: 'thetes' } });
111
138
  const r = await get('/provisioning/instances/18');