@bongos/core 1.19.804 → 1.19.805
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 +257 -237
- package/.claude/skills/ask-for-help/SKILL.md +6 -6
- package/.claude/skills/backlog-review/SKILL.md +1 -1
- package/.claude/skills/blocker-review/SKILL.md +7 -7
- package/.claude/skills/blocker-solve/SKILL.md +5 -5
- package/.claude/skills/bug-triage/SKILL.md +7 -7
- package/.claude/skills/builder-claim/SKILL.md +3 -3
- package/.claude/skills/builder-cost/SKILL.md +2 -2
- package/.claude/skills/builder-end/SKILL.md +2 -2
- package/.claude/skills/builder-exit/SKILL.md +7 -7
- package/.claude/skills/builder-key/SKILL.md +2 -2
- package/.claude/skills/builder-reauth/SKILL.md +2 -2
- package/.claude/skills/builder-redteam/SKILL.md +7 -7
- package/.claude/skills/builder-release/SKILL.md +2 -2
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/builder-setup/SKILL.md +3 -3
- package/.claude/skills/builder-ship/SKILL.md +1 -1
- package/.claude/skills/builder-stage/SKILL.md +1 -1
- package/.claude/skills/builder-start/SKILL.md +1 -1
- package/.claude/skills/fix-task/SKILL.md +4 -4
- package/.claude/skills/goal-create/SKILL.md +18 -18
- package/.claude/skills/goal-review/SKILL.md +7 -7
- package/.claude/skills/grade-audit/SKILL.md +5 -5
- package/.claude/skills/grade-recover/SKILL.md +4 -4
- package/.claude/skills/grader-health/SKILL.md +6 -6
- package/.claude/skills/idea-triage/SKILL.md +14 -14
- package/.claude/skills/merge-mode/SKILL.md +3 -3
- package/.claude/skills/planning-session/SKILL.md +20 -20
- package/.claude/skills/priority-session/SKILL.md +10 -10
- package/.claude/skills/recall/SKILL.md +1 -1
- package/.claude/skills/scan-before-install/SKILL.md +3 -3
- package/.claude/skills/status/SKILL.md +2 -2
- package/.claude/skills/strand-fix/SKILL.md +2 -2
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +2 -0
- package/clients/bongos-client/index.cjs +2 -0
- package/clients/bongos-client/index.d.ts +2 -0
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/api/openapi.json +45 -11
- package/docs/api-reference.md +11 -10
- package/docs/module-api-changelog.md +2 -0
- package/modules/builder-settings/profile-nudge-prefs.js +1 -1
- package/modules/builder-settings/render-prefs.js +1 -1
- package/modules/dev-box/app/README.md +1 -1
- package/modules/dev-box/app/src/gds-client.js +11 -9
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
- package/modules/dev-box/app/test/unit.mjs +13 -13
- package/modules/dev-box/box-access.js +3 -3
- package/modules/dev-box/box-onboard.js +7 -7
- package/modules/discord/bug-attachments.js +1 -1
- package/modules/economy/cost-classify.js +6 -6
- package/modules/grading/grader-rubric.json +1 -1
- package/modules/grading/grader-score.js +1 -1
- package/modules/hall-ui/module.json +1 -1
- package/modules/hall-ui/public/drachmae.js +3 -3
- package/modules/hall-ui/public/idea.js +1 -1
- package/modules/hall-ui/public/md-reader.js +1 -1
- package/modules/hall-ui/public/people.html +1 -1
- package/modules/hall-ui/public/people.js +2 -2
- package/modules/hall-ui/public/primer.js +4 -4
- package/modules/hall-ui/public/roster.js +1 -1
- package/modules/hall-ui/public/shell.js +1 -1
- package/modules/hall-ui/public/task.js +1 -1
- package/modules/ideas/inbox.js +2 -2
- package/modules/lifecycle/db-analytics.js +1 -1
- package/modules/lifecycle/done-when.js +4 -4
- package/modules/lifecycle/version-close.js +1 -1
- package/modules/memory/learnings.js +2 -2
- package/modules/memory/memory.js +1 -1
- package/modules/onboarding/onboarding.js +1 -1
- package/modules/platform-identity/routes/my-projects.js +1 -1
- package/modules/platform-identity/routes/sso.js +2 -2
- package/modules/public-landing/public/index.html +2 -2
- package/modules/public-landing/public/projects-floor.states.json +1 -1
- package/modules/public-landing/public/projects.html +1 -1
- package/modules/public-landing/public/projects.states.json +1 -1
- package/modules/sessions/db.js +120 -0
- package/modules/sessions/module.json +2 -2
- package/modules/sessions/pollers/session-upload-health.js +111 -0
- package/modules/sessions/pulse.js +2 -2
- package/modules/sessions/routes/sessions.js +46 -0
- package/modules/sessions/upload-health.js +197 -0
- package/modules/status-ui/module.json +1 -1
- package/modules/status-ui/public/explore.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/agent-invoke.js +3 -3
- package/scripts/gds/api.js +4 -4
- package/scripts/gds/api.sh +1 -1
- package/scripts/gds/architect-audit.js +1 -1
- package/scripts/gds/artifact-audit.js +2 -2
- package/scripts/gds/audit-ships.js +2 -2
- package/scripts/gds/backfill-cost.js +1 -1
- package/scripts/gds/backfill-sessions.js +1 -1
- package/scripts/gds/backfill-subagent-rewards.js +1 -1
- package/scripts/gds/backfill-task-rewards.js +2 -2
- package/scripts/gds/box-auth-check.js +1 -1
- package/scripts/gds/box-sync.js +3 -3
- package/scripts/gds/box.js +10 -10
- package/scripts/gds/build-cli-package.js +3 -3
- package/scripts/gds/capture.js +2 -2
- package/scripts/gds/ci-grade.js +1 -1
- package/scripts/gds/claim-recall.js +2 -2
- package/scripts/gds/cli-lib.js +3 -3
- package/scripts/gds/context-pack.js +1 -1
- package/scripts/gds/copy-apply.js +2 -2
- package/scripts/gds/dev-lib.js +2 -2
- package/scripts/gds/fetch-art-key.js +2 -2
- package/scripts/gds/fetch-sound-prefs.js +3 -3
- package/scripts/gds/grade-smoke.js +1 -1
- package/scripts/gds/hooks/pre-push.js +1 -1
- package/scripts/gds/init.js +9 -9
- package/scripts/gds/key-card.js +1 -1
- package/scripts/gds/learning-capture.js +2 -2
- package/scripts/gds/linkify-refs.js +2 -2
- package/scripts/gds/local-preview-lib.js +1 -1
- package/scripts/gds/login.js +11 -10
- package/scripts/gds/main-audit.js +1 -1
- package/scripts/gds/newcomer-floor.config.json +1 -1
- package/scripts/gds/newcomer-floor.js +2 -2
- package/scripts/gds/newcomer-floor.templates.json +2 -2
- package/scripts/gds/onboarding-ship.js +1 -1
- package/scripts/gds/paste-token.js +3 -3
- package/scripts/gds/portability-smoke-memory.sh +5 -5
- package/scripts/gds/prove-strict-versioning.js +2 -2
- package/scripts/gds/provision-net.js +2 -2
- package/scripts/gds/provision-units.js +3 -3
- package/scripts/gds/pulse.js +2 -2
- package/scripts/gds/push-path-brief.js +2 -2
- package/scripts/gds/reauth.js +1 -1
- package/scripts/gds/recall.js +1 -1
- package/scripts/gds/redteam-patrol.js +3 -3
- package/scripts/gds/render-ideas.js +5 -5
- package/scripts/gds/repo-metrics.js +1 -1
- package/scripts/gds/sandbox-stage.js +3 -3
- package/scripts/gds/seed-adopt-tasks.js +3 -3
- package/scripts/gds/seed-board-room-tasks.js +1 -1
- package/scripts/gds/seed-bongos-app-tasks.js +2 -2
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
- package/scripts/gds/seed-bongos-tasks.js +5 -5
- package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
- package/scripts/gds/seed-bv1-community-tasks.js +1 -1
- package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
- package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
- package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
- package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
- package/scripts/gds/seed-gds-v4-tasks.js +3 -3
- package/scripts/gds/seed-medusa-tasks.js +1 -1
- package/scripts/gds/seed-productization-tasks.js +1 -1
- package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
- package/scripts/gds/seed-provisioning-tasks.js +2 -2
- package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
- package/scripts/gds/seed-v2-world-tasks.js +2 -2
- package/scripts/gds/seed-verify-criteria.js +1 -1
- package/scripts/gds/session-digest.js +1 -1
- package/scripts/gds/session.js +2 -2
- package/scripts/gds/setup.js +7 -7
- package/scripts/gds/ship-flow.js +3 -3
- package/scripts/gds/ship-grade-steps.js +3 -3
- package/scripts/gds/ship-memory-sync.js +1 -1
- package/scripts/gds/ship-session-upload.js +3 -3
- package/scripts/gds/smoke-batch-claim.sh +10 -10
- package/scripts/gds/smoke-batch-release.sh +14 -14
- package/scripts/gds/smoke-claim-consistency.sh +19 -19
- package/scripts/gds/smoke-dependencies.sh +9 -9
- package/scripts/gds/smoke-write.sh +11 -11
- package/scripts/gds/start.js +1 -1
- package/scripts/gds/status.js +2 -2
- package/scripts/gds/strand-watch.js +1 -1
- package/scripts/gds/triage.js +4 -4
- package/scripts/gds/version-close.js +2 -2
- package/scripts/hall-preview/README.md +1 -1
- package/scripts/hall-preview/server.js +1 -1
- package/src/bongos/auth-admission.js +3 -3
- package/src/bongos/auth-idp.js +2 -2
- package/src/bongos/auth.js +3 -3
- package/src/bongos/db.js +2 -2
- package/src/bongos/llm-cache.js +2 -2
- package/src/bongos/metrics.js +1 -1
- package/src/bongos/middleware/audit.js +3 -3
- package/src/bongos/middleware/rate-limit.js +1 -1
- package/src/bongos/platform-visibility-gate.js +2 -2
- package/src/bongos/routes/_helpers.js +1 -1
- package/src/bongos/routes/audit-log.js +1 -1
- package/src/bongos/routes/auth.js +5 -5
- package/src/bongos/routes/backup.js +1 -1
- package/src/bongos/routes/builders.js +1 -1
- package/src/bongos/routes/instance.js +1 -1
- package/src/bongos/routes/live.js +1 -1
- package/src/bongos/routes/me.js +2 -2
- package/src/bongos/routes/modules.js +2 -2
- package/src/bongos/routes/public.js +1 -1
- package/src/bongos/routes/security.js +4 -4
- package/src/bongos/routes.js +1 -1
- package/src/bongos/serve-internal.js +6 -6
- package/src/branding.js +1 -1
- package/src/module-api.js +1 -1
- package/src/module-seams.js +2 -2
- package/src/platform-server.js +2 -2
- package/tests/api_alias_exceptions.mjs +67 -0
- package/tests/application_echo.mjs +12 -12
- package/tests/artifact_audit.mjs +1 -1
- package/tests/auth_page_gate.mjs +4 -4
- package/tests/auth_web_recovery.mjs +11 -11
- package/tests/bongos_login.mjs +7 -4
- package/tests/box_env.mjs +6 -6
- package/tests/bug_attachments.mjs +1 -1
- package/tests/cli_sessions.mjs +1 -1
- package/tests/dev_lib.mjs +1 -1
- package/tests/discord_bugs.mjs +2 -2
- package/tests/discord_inbound.mjs +2 -2
- package/tests/explore_visible_states.mjs +1 -1
- package/tests/government_page_gates.mjs +1 -1
- package/tests/hall_reference_world.mjs +1 -1
- package/tests/idea_ideate_full.mjs +1 -1
- package/tests/idp_federation.mjs +2 -2
- package/tests/llm-cache.mjs +1 -1
- package/tests/manage_manifest_shared_read.mjs +3 -3
- package/tests/people_directory_clip.mjs +1 -1
- package/tests/planning_session_skill.mjs +1 -1
- package/tests/platform_visibility_gate.mjs +15 -15
- package/tests/profile_route.mjs +25 -25
- package/tests/projects_hub.mjs +2 -2
- package/tests/provision.mjs +2 -2
- package/tests/provision_settings_apply.mjs +4 -4
- package/tests/sandbox_stage.mjs +8 -8
- package/tests/scouting_owner_access_and_reach.mjs +3 -3
- package/tests/session_upload_health.mjs +329 -0
- package/tests/setup_device_flow_fallback.mjs +1 -1
- package/tests/skill_ask_for_help.mjs +3 -3
- package/tests/skill_grade_audit.mjs +2 -2
- package/tests/skill_grader_health.mjs +3 -3
- package/tests/smoke_write_contract.mjs +1 -1
package/tests/profile_route.mjs
CHANGED
|
@@ -198,7 +198,7 @@ function buildApp() {
|
|
|
198
198
|
const app = express();
|
|
199
199
|
app.use(express.json());
|
|
200
200
|
app.use(attachFail); // res.fail() ahead of the routers, exactly as the real app does
|
|
201
|
-
app.use('/api/
|
|
201
|
+
app.use('/api/bongos', buildBuildersRouter());
|
|
202
202
|
return app;
|
|
203
203
|
}
|
|
204
204
|
|
|
@@ -227,7 +227,7 @@ function get(port, path, headers) {
|
|
|
227
227
|
const { server, port } = await listen(buildApp());
|
|
228
228
|
|
|
229
229
|
await t('known id → 200 with the public field subset', async () => {
|
|
230
|
-
const r = await get(port, '/api/
|
|
230
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
231
231
|
assert.equal(r.status, 200);
|
|
232
232
|
assert.ok(r.json && r.json.builder, 'response has a builder object');
|
|
233
233
|
for (const k of PUBLIC_KEYS) {
|
|
@@ -242,7 +242,7 @@ await t('known id → 200 with the public field subset', async () => {
|
|
|
242
242
|
});
|
|
243
243
|
|
|
244
244
|
await t('known id → NO private column leaks on the builder object', async () => {
|
|
245
|
-
const r = await get(port, '/api/
|
|
245
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
246
246
|
assert.equal(r.status, 200);
|
|
247
247
|
for (const k of PRIVATE_KEYS) {
|
|
248
248
|
assert.ok(!(k in r.json.builder), `private field "${k}" must NOT be present on the builder`);
|
|
@@ -250,7 +250,7 @@ await t('known id → NO private column leaks on the builder object', async () =
|
|
|
250
250
|
});
|
|
251
251
|
|
|
252
252
|
await t('known id → no secret sentinel leaks ANYWHERE in the response body', async () => {
|
|
253
|
-
const r = await get(port, '/api/
|
|
253
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
254
254
|
assert.equal(r.status, 200);
|
|
255
255
|
for (const secret of [SECRET_EMAIL, SECRET_USER, SECRET_REASON]) {
|
|
256
256
|
assert.ok(!r.text.includes(secret), `response body must not contain the secret "${secret}"`);
|
|
@@ -258,13 +258,13 @@ await t('known id → no secret sentinel leaks ANYWHERE in the response body', a
|
|
|
258
258
|
});
|
|
259
259
|
|
|
260
260
|
await t('unknown id → 404 builder_not_found', async () => {
|
|
261
|
-
const r = await get(port, '/api/
|
|
261
|
+
const r = await get(port, '/api/bongos/builders/99999/profile');
|
|
262
262
|
assert.equal(r.status, 404);
|
|
263
263
|
assert.equal(r.json && r.json.error && r.json.error.code, 'builder_not_found');
|
|
264
264
|
});
|
|
265
265
|
|
|
266
266
|
await t('non-numeric id → 400 bad_builder_id', async () => {
|
|
267
|
-
const r = await get(port, '/api/
|
|
267
|
+
const r = await get(port, '/api/bongos/builders/not-a-number/profile');
|
|
268
268
|
assert.equal(r.status, 400);
|
|
269
269
|
assert.equal(r.json && r.json.error && r.json.error.code, 'bad_builder_id');
|
|
270
270
|
});
|
|
@@ -275,7 +275,7 @@ await t('non-numeric id → 400 bad_builder_id', async () => {
|
|
|
275
275
|
// hub posture for the tests below.
|
|
276
276
|
|
|
277
277
|
await t('hub port ABSENT → no cross_project key + the cacheable posture stays', async () => {
|
|
278
|
-
const r = await get(port, '/api/
|
|
278
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
279
279
|
assert.equal(r.status, 200);
|
|
280
280
|
assert.ok(!('cross_project' in r.json), 'cross_project must be absent on a non-hub instance');
|
|
281
281
|
assert.equal(r.headers['cache-control'], 'public, max-age=60');
|
|
@@ -292,7 +292,7 @@ seams.registerProvider('platform-identity.hub', {
|
|
|
292
292
|
});
|
|
293
293
|
|
|
294
294
|
await t('hub port present → cross_project carries exactly the whitelist shape', async () => {
|
|
295
|
-
const r = await get(port, '/api/
|
|
295
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
296
296
|
assert.equal(r.status, 200);
|
|
297
297
|
const cp = r.json.cross_project;
|
|
298
298
|
assert.ok(cp, 'cross_project attached when the port resolves');
|
|
@@ -302,7 +302,7 @@ await t('hub port present → cross_project carries exactly the whitelist shape'
|
|
|
302
302
|
});
|
|
303
303
|
|
|
304
304
|
await t('hub port present → module-internal sentinels leak NOWHERE in the response', async () => {
|
|
305
|
-
const r = await get(port, '/api/
|
|
305
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
306
306
|
assert.equal(r.status, 200);
|
|
307
307
|
for (const secret of [SECRET_CLIENT_ID, SECRET_PROJECT_NAME, SECRET_EMAIL, SECRET_USER, SECRET_REASON]) {
|
|
308
308
|
assert.ok(!r.text.includes(secret), `response body must not contain "${secret}"`);
|
|
@@ -311,13 +311,13 @@ await t('hub port present → module-internal sentinels leak NOWHERE in the resp
|
|
|
311
311
|
});
|
|
312
312
|
|
|
313
313
|
await t('hub port present → hide must beat the cache: Cache-Control is no-store', async () => {
|
|
314
|
-
const r = await get(port, '/api/
|
|
314
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
315
315
|
assert.equal(r.headers['cache-control'], 'no-store');
|
|
316
316
|
});
|
|
317
317
|
|
|
318
318
|
await t('hub port returns null (hidden/provisional/none) → cross_project: null, still no-store', async () => {
|
|
319
319
|
hubExtras = null;
|
|
320
|
-
const r = await get(port, '/api/
|
|
320
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
321
321
|
assert.equal(r.status, 200);
|
|
322
322
|
assert.ok('cross_project' in r.json, 'the key is present on the hub');
|
|
323
323
|
assert.equal(r.json.cross_project, null, 'null — no partial numbers, indistinguishable from no-account');
|
|
@@ -472,7 +472,7 @@ const buildScoutingRoutes = require('../modules/platform-identity/routes/scoutin
|
|
|
472
472
|
hubPublicRead = (githubId) => pi.getPublicProfileExtras(githubId, { pool: engine });
|
|
473
473
|
|
|
474
474
|
await t('R06.1 a two-project builder\'s COMBINED record shows to another account', async () => {
|
|
475
|
-
const r = await get(port, '/api/
|
|
475
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
476
476
|
assert.equal(r.status, 200);
|
|
477
477
|
const cp = r.json.cross_project;
|
|
478
478
|
assert.ok(cp, 'the record is served');
|
|
@@ -500,7 +500,7 @@ await t('R06.1 a name needs the map AND the Public door — every other shape is
|
|
|
500
500
|
try {
|
|
501
501
|
for (const [label, catalog] of Object.entries(unnamed)) {
|
|
502
502
|
other.catalog = catalog;
|
|
503
|
-
const r = await get(port, '/api/
|
|
503
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
504
504
|
const cp = r.json.cross_project;
|
|
505
505
|
assert.deepEqual(cp.projects.map((p) => p.name), [pub.name], `${label}: only the Public project is named`);
|
|
506
506
|
assert.equal(cp.more_projects, 1, `${label}: counted`);
|
|
@@ -509,7 +509,7 @@ await t('R06.1 a name needs the map AND the Public door — every other shape is
|
|
|
509
509
|
// The positive control: the same row IS named once Public and on the map, so the
|
|
510
510
|
// refusals above are the door, not a fixture nothing could ever name.
|
|
511
511
|
other.catalog = { ...original, visibility: 'public' };
|
|
512
|
-
const r = await get(port, '/api/
|
|
512
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
513
513
|
assert.deepEqual(r.json.cross_project.projects.map((p) => p.name), [pub.name, SECRET_PROJECT_NAME]);
|
|
514
514
|
} finally {
|
|
515
515
|
other.catalog = original;
|
|
@@ -517,8 +517,8 @@ await t('R06.1 a name needs the map AND the Public door — every other shape is
|
|
|
517
517
|
});
|
|
518
518
|
|
|
519
519
|
await t('R06.1 the record is viewer-INDEPENDENT — another account sees the same body', async () => {
|
|
520
|
-
const anon = await get(port, '/api/
|
|
521
|
-
const other = await get(port, '/api/
|
|
520
|
+
const anon = await get(port, '/api/bongos/builders/95/profile');
|
|
521
|
+
const other = await get(port, '/api/bongos/builders/95/profile', { Cookie: 'gds_session=some-other-builder' });
|
|
522
522
|
assert.equal(other.status, 200);
|
|
523
523
|
assert.equal(other.text, anon.text, 'one response shape for every reader (ADR 0171 D4)');
|
|
524
524
|
});
|
|
@@ -564,7 +564,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
|
|
|
564
564
|
try {
|
|
565
565
|
// (a) a module-internal key on the object itself.
|
|
566
566
|
hubPublicRead = async () => ({ ...(await rollup()), client_id: SECRET_CLIENT_ID });
|
|
567
|
-
let r = await get(port, '/api/
|
|
567
|
+
let r = await get(port, '/api/bongos/builders/95/profile');
|
|
568
568
|
assert.throws(() => assertCrossProjectContract(r.json.cross_project, r.text),
|
|
569
569
|
/cross_project keys are exactly the contract/, 'an extra top-level key must turn the guard red');
|
|
570
570
|
|
|
@@ -573,7 +573,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
|
|
|
573
573
|
const cp = await rollup();
|
|
574
574
|
return { ...cp, projects: cp.projects.map((p) => ({ ...p, is_public: true })) };
|
|
575
575
|
};
|
|
576
|
-
r = await get(port, '/api/
|
|
576
|
+
r = await get(port, '/api/bongos/builders/95/profile');
|
|
577
577
|
assert.throws(() => assertCrossProjectContract(r.json.cross_project, r.text),
|
|
578
578
|
/project rows carry only the whitelisted keys/, 'an extra project-row key must turn the guard red');
|
|
579
579
|
|
|
@@ -583,7 +583,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
|
|
|
583
583
|
const cp = await rollup();
|
|
584
584
|
return { ...cp, projects: [{ ...cp.projects[0], name: SECRET_PROJECT_NAME }] };
|
|
585
585
|
};
|
|
586
|
-
r = await get(port, '/api/
|
|
586
|
+
r = await get(port, '/api/bongos/builders/95/profile');
|
|
587
587
|
assert.deepEqual(Object.keys(r.json.cross_project).sort(), [...CP_PUBLIC_KEYS].sort(),
|
|
588
588
|
'the planted leak is shape-legal — only the sentinel scan can catch it');
|
|
589
589
|
assert.throws(() => assertCrossProjectContract(r.json.cross_project, r.text),
|
|
@@ -594,7 +594,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
|
|
|
594
594
|
});
|
|
595
595
|
|
|
596
596
|
await t('R06.2 hide_stats removes the record on the IMMEDIATE next load', async () => {
|
|
597
|
-
const before = await get(port, '/api/
|
|
597
|
+
const before = await get(port, '/api/bongos/builders/95/profile');
|
|
598
598
|
assert.ok(before.json.cross_project, 'public before the flip');
|
|
599
599
|
assert.equal(before.headers['cache-control'], 'no-store');
|
|
600
600
|
|
|
@@ -604,7 +604,7 @@ await t('R06.2 hide_stats removes the record on the IMMEDIATE next load', async
|
|
|
604
604
|
assert.equal(row.hide_stats, true, 'the write path set the flag');
|
|
605
605
|
|
|
606
606
|
// No sleep, no second server, no cache warm-up: the very next load.
|
|
607
|
-
const after = await get(port, '/api/
|
|
607
|
+
const after = await get(port, '/api/bongos/builders/95/profile');
|
|
608
608
|
assert.equal(after.status, 200);
|
|
609
609
|
assert.equal(after.json.cross_project, null, 'gone on the next load');
|
|
610
610
|
assert.equal(after.headers['cache-control'], 'no-store', 'hide must beat the cache (ADR 0171 D5)');
|
|
@@ -616,7 +616,7 @@ await t('R06.5 no PARTIAL numbers survive the hide (a count beside a hidden tota
|
|
|
616
616
|
// Set the flag here too, so this proof stands on its own rather than on
|
|
617
617
|
// whatever R06.2 left behind.
|
|
618
618
|
await pi.setAccountHideStats({ githubId: HUB_GITHUB_ID, githubLogin: 'jaxri', hide: true }, { pool: engine });
|
|
619
|
-
const r = await get(port, '/api/
|
|
619
|
+
const r = await get(port, '/api/bongos/builders/95/profile');
|
|
620
620
|
assert.equal(r.json.cross_project, null);
|
|
621
621
|
for (const key of ['totals', 'works_shipped', 'more_projects', 'last_active', 'rank_held']) {
|
|
622
622
|
assert.ok(!r.text.includes(key), `nothing derived from the rollup may survive — found "${key}"`);
|
|
@@ -632,12 +632,12 @@ await t('R06.5 no PARTIAL numbers survive the hide (a count beside a hidden tota
|
|
|
632
632
|
|
|
633
633
|
const scoutApp = express();
|
|
634
634
|
scoutApp.use(attachFail);
|
|
635
|
-
scoutApp.use('/api/
|
|
635
|
+
scoutApp.use('/api/bongos', buildScoutingRoutes());
|
|
636
636
|
const scout = await listen(scoutApp);
|
|
637
637
|
|
|
638
638
|
await t('R06.3 GET /scouting drops the hidden, the provisional AND the private builder', async () => {
|
|
639
639
|
engine.calls.length = 0;
|
|
640
|
-
const r = await get(scout.port, '/api/
|
|
640
|
+
const r = await get(scout.port, '/api/bongos/scouting');
|
|
641
641
|
assert.equal(r.status, 200);
|
|
642
642
|
const logins = r.json.builders.map((b) => b.github_login);
|
|
643
643
|
assert.deepEqual(logins, ['r06-visible'],
|
|
@@ -662,7 +662,7 @@ await t('R06.3 the /people page reads /scouting and nothing else', async () => {
|
|
|
662
662
|
// assembled is the page's business.
|
|
663
663
|
const args = [...sourceOf('modules/hall-ui/public/people.js').matchAll(/\bfetch\(\s*([^,)]+)/g)].map((m) => m[1].trim());
|
|
664
664
|
assert.equal(args.length, 1, '/people has exactly one data source');
|
|
665
|
-
assert.match(args[0], /^'\/api\/
|
|
665
|
+
assert.match(args[0], /^'\/api\/bongos\/scouting\?limit='/,
|
|
666
666
|
'and it is the scouting rollup — nothing may re-enter through a second endpoint');
|
|
667
667
|
});
|
|
668
668
|
|
package/tests/projects_hub.mjs
CHANGED
|
@@ -1426,7 +1426,7 @@ test('what the project RUNS comes only from its own manifest, and every answer i
|
|
|
1426
1426
|
const runs = fnHub('loadVisRuns');
|
|
1427
1427
|
const manifest = fnHub('ensureManifest');
|
|
1428
1428
|
assert.match(runs, /inst\.status !== 'active' \|\| !inst\.domain/, 'only a live project with an address can be asked');
|
|
1429
|
-
assert.match(manifest, /'https:\/\/' \+ domain \+ '\/api\/
|
|
1429
|
+
assert.match(manifest, /'https:\/\/' \+ domain \+ '\/api\/bongos\/instance'/,
|
|
1430
1430
|
'the same public GET /instance the platform’s runner reads after a restart');
|
|
1431
1431
|
assert.doesNotMatch(runs, /fetch\(/, 'the card fires no GET of its own — one manifest read serves the pair (task 1003554)');
|
|
1432
1432
|
assert.match(runs, /m\.brand && m\.brand\.project/);
|
|
@@ -1600,7 +1600,7 @@ test('the join door is read on entry + tab return, like every other settings sec
|
|
|
1600
1600
|
// door yet, and a line that could only ever say "your project doesn’t report
|
|
1601
1601
|
// this" is worse than no line. The read-back lands with the enforcement.
|
|
1602
1602
|
const load = fnHub('loadDoor');
|
|
1603
|
-
assert.doesNotMatch(load, /api\/
|
|
1603
|
+
assert.doesNotMatch(load, /api\/bongos\/instance/, 'this section asks the project’s manifest nothing');
|
|
1604
1604
|
});
|
|
1605
1605
|
|
|
1606
1606
|
test('the joinability choices are the platform’s vocabulary, each in plain words, and the pick is a real radio group', () => {
|
package/tests/provision.mjs
CHANGED
|
@@ -220,7 +220,7 @@ t('webEnvBody: an instance is never pinned to the neutral pack, so it serves its
|
|
|
220
220
|
// into every instance's web.env — a leftover from the shared-checkout co-tenant model. Under
|
|
221
221
|
// ADR 0108 each instance has its own checkout and its own config/branding.json, and
|
|
222
222
|
// src/branding.js's ENV_OVERRIDES cover domains/auth.idp/landing but NEVER identity.productName.
|
|
223
|
-
// So the pin made every hosted instance answer GET /api/
|
|
223
|
+
// So the pin made every hosted instance answer GET /api/bongos/instance with the PLATFORM's name:
|
|
224
224
|
// hermeslines-marketing, mercury and demo all said "Cloud Bongos" while their own packs on disk
|
|
225
225
|
// said otherwise, and `bongos login <instance>` greeted newcomers with the wrong project.
|
|
226
226
|
const b = P.webEnvBody({ ...coTenant, domain: 'mercury.example.com' });
|
|
@@ -262,7 +262,7 @@ t('identityVerdict: a live instance serving the PLATFORM name is caught, not shr
|
|
|
262
262
|
|
|
263
263
|
t('identityCmd: probes the manifest over loopback, like healthzCmd', () => {
|
|
264
264
|
const N = require('../scripts/gds/provision-net.js');
|
|
265
|
-
assert.match(N.identityCmd({ port: 3011 }), /127\.0\.0\.1:3011\/api\/
|
|
265
|
+
assert.match(N.identityCmd({ port: 3011 }), /127\.0\.0\.1:3011\/api\/bongos\/instance/);
|
|
266
266
|
});
|
|
267
267
|
|
|
268
268
|
t('webEnvBody: a domain writes the single-host origin overrides so the hall loads (task 1972)', () => {
|
|
@@ -151,7 +151,7 @@ t('null (unknown) when the manifest carries no project block — a core that pre
|
|
|
151
151
|
assert.equal(P.settingsConsumed(JSON.stringify({ brand: { project: 'nope' } }), GATED), null);
|
|
152
152
|
});
|
|
153
153
|
t('instanceManifestCmd asks the instance on loopback, like healthzCmd', () => {
|
|
154
|
-
assert.equal(P.instanceManifestCmd({ port: 3010 }), 'curl -sS --max-time 5 http://127.0.0.1:3010/api/
|
|
154
|
+
assert.equal(P.instanceManifestCmd({ port: 3010 }), 'curl -sS --max-time 5 http://127.0.0.1:3010/api/bongos/instance');
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
// ── the handler ──────────────────────────────────────────────────────────────
|
|
@@ -166,7 +166,7 @@ function recorder({ apply = false, envBody = LIVE_ENV, readFails = false, health
|
|
|
166
166
|
cmds.push(cmd);
|
|
167
167
|
if (/\bcat /.test(cmd)) return readFails ? { ok: true, stdout: '', softFailed: true } : { ok: true, stdout: envBody };
|
|
168
168
|
if (/healthz/.test(cmd)) return healthzFails ? { ok: true, stdout: '', softFailed: true } : { ok: true, stdout: '{"ok":true}' };
|
|
169
|
-
if (/api\/
|
|
169
|
+
if (/api\/bongos\/instance/.test(cmd)) return { ok: true, stdout: manifestOut };
|
|
170
170
|
if (/systemctl restart/.test(cmd) && restartThrows && apply) throw new Error(`Command failed: ${cmd}`);
|
|
171
171
|
return { ok: true, stdout: '' };
|
|
172
172
|
};
|
|
@@ -218,7 +218,7 @@ await ta('--apply, active standalone: read web.env → patch ONLY the settings l
|
|
|
218
218
|
assert.ok(idx(/systemctl restart spike/) >= 0, 'RESTART (not reload) so the process re-reads its env');
|
|
219
219
|
assert.ok(idx(/cat /) < idx(/restart spike/), 'read before restart');
|
|
220
220
|
assert.ok(idx(/restart spike/) < idx(/healthz/), 'healthz after the restart');
|
|
221
|
-
assert.ok(idx(/healthz/) < idx(/api\/
|
|
221
|
+
assert.ok(idx(/healthz/) < idx(/api\/bongos\/instance/), 'the read-back only after it answers');
|
|
222
222
|
assert.ok(!cmds.some((c) => /systemctl (stop|disable)|caddy|box-dns/.test(c)), 'no teardown / DNS / caddy legs — settings only');
|
|
223
223
|
});
|
|
224
224
|
|
|
@@ -355,7 +355,7 @@ await ta('--apply: a restart that never answers /healthz is a VERDICT after the
|
|
|
355
355
|
assert.deepEqual(probes, [{ id: 18, up: false }]);
|
|
356
356
|
assert.match(events[0].detail, /not answering \/healthz yet/);
|
|
357
357
|
assert.equal(cmds.filter((c) => /healthz/.test(c)).length, MANIFEST_VERIFY_TRIES, 'the same patience as the manifest probe (F23) — a slow boot is not slandered');
|
|
358
|
-
assert.ok(!cmds.some((c) => /api\/
|
|
358
|
+
assert.ok(!cmds.some((c) => /api\/bongos\/instance/.test(c)), 'no manifest probe when it never answered');
|
|
359
359
|
});
|
|
360
360
|
|
|
361
361
|
await ta('--apply: a domainless instance that answers records up=true immediately (provisionInstance step-7 rule)', async () => {
|
package/tests/sandbox_stage.mjs
CHANGED
|
@@ -242,9 +242,9 @@ function boxDeps(markerFile, overrides = {}) {
|
|
|
242
242
|
return '';
|
|
243
243
|
},
|
|
244
244
|
// task 1002607: emulate a real PREVIEW — 200 on the health URL, 404 on the
|
|
245
|
-
// /api/
|
|
245
|
+
// /api/bongos/healthz discriminator (the game-only entry mounts no /api/bongos).
|
|
246
246
|
// A flat always-200 mock would now read as "the MAIN server answered".
|
|
247
|
-
fetchImpl: async (url) => ({ status: String(url).includes('/api/
|
|
247
|
+
fetchImpl: async (url) => ({ status: String(url).includes('/api/bongos/healthz') ? 404 : 200 }),
|
|
248
248
|
markerPath: markerFile,
|
|
249
249
|
cwd: tmp,
|
|
250
250
|
pollMs: 1,
|
|
@@ -541,7 +541,7 @@ await ta('1002607 waitHealthy: 404 at the health URL is NOT healthy (was: anythi
|
|
|
541
541
|
|
|
542
542
|
await ta('1002607 waitHealthy: a 200 answered by the MAIN server (api healthz 200) is an impostor, not a healthy preview', async () => {
|
|
543
543
|
// The full server binds the same 127.0.0.1:3000 — root answers 200, and so does
|
|
544
|
-
// /api/
|
|
544
|
+
// /api/bongos/healthz. The game-only preview (ADR 0052) would 404 the latter.
|
|
545
545
|
const r = await sbx.waitHealthy({ fetchImpl: async () => ({ status: 200 }), timeoutMs: 1000, pollMs: 1 });
|
|
546
546
|
assert.equal(r.ok, false, 'a dead preview must not report healthy off the main server');
|
|
547
547
|
assert.match(r.reason, /MAIN server/);
|
|
@@ -550,7 +550,7 @@ await ta('1002607 waitHealthy: a 200 answered by the MAIN server (api healthz 20
|
|
|
550
550
|
|
|
551
551
|
await ta('1002607 waitHealthy: a real preview (root 200, api healthz 404) is healthy', async () => {
|
|
552
552
|
const r = await sbx.waitHealthy({
|
|
553
|
-
fetchImpl: async (url) => ({ status: String(url).includes('/api/
|
|
553
|
+
fetchImpl: async (url) => ({ status: String(url).includes('/api/bongos/healthz') ? 404 : 200 }),
|
|
554
554
|
timeoutMs: 1000, pollMs: 1,
|
|
555
555
|
});
|
|
556
556
|
assert.equal(r.ok, true);
|
|
@@ -559,7 +559,7 @@ await ta('1002607 waitHealthy: a real preview (root 200, api healthz 404) is hea
|
|
|
559
559
|
await ta('1002607 waitHealthy: a discriminator probe that ERRORS counts as "not the main server" (preview healthy)', async () => {
|
|
560
560
|
const r = await sbx.waitHealthy({
|
|
561
561
|
fetchImpl: async (url) => {
|
|
562
|
-
if (String(url).includes('/api/
|
|
562
|
+
if (String(url).includes('/api/bongos/healthz')) throw new Error('ECONNREFUSED on a path the preview never mounts');
|
|
563
563
|
return { status: 200 };
|
|
564
564
|
},
|
|
565
565
|
timeoutMs: 1000, pollMs: 1,
|
|
@@ -568,8 +568,8 @@ await ta('1002607 waitHealthy: a discriminator probe that ERRORS counts as "not
|
|
|
568
568
|
});
|
|
569
569
|
|
|
570
570
|
t('1002607 apiHealthzProbeUrl: same origin as the health URL, api path; null on garbage', () => {
|
|
571
|
-
assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3000/'), 'http://127.0.0.1:3000/api/
|
|
572
|
-
assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3100/healthz'), 'http://127.0.0.1:3100/api/
|
|
571
|
+
assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3000/'), 'http://127.0.0.1:3000/api/bongos/healthz');
|
|
572
|
+
assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3100/healthz'), 'http://127.0.0.1:3100/api/bongos/healthz');
|
|
573
573
|
assert.equal(sbx.apiHealthzProbeUrl('not a url'), null);
|
|
574
574
|
});
|
|
575
575
|
|
|
@@ -599,7 +599,7 @@ function localDeps(markerFile, overrides = {}) {
|
|
|
599
599
|
},
|
|
600
600
|
execFileSync: (cmd, args, opts) => (cmd === 'git' ? execFileSync(cmd, args, opts) : ''),
|
|
601
601
|
// task 1002607: preview-shaped mock — health 200, API-healthz discriminator 404.
|
|
602
|
-
fetchImpl: async (url) => ({ status: String(url).includes('/api/
|
|
602
|
+
fetchImpl: async (url) => ({ status: String(url).includes('/api/bongos/healthz') ? 404 : 200 }),
|
|
603
603
|
markerPath: markerFile,
|
|
604
604
|
cwd: tmp,
|
|
605
605
|
pollMs: 1,
|
|
@@ -364,7 +364,7 @@ const { attachFail } = require('../src/bongos/middleware/error-envelope.js');
|
|
|
364
364
|
|
|
365
365
|
const app = express();
|
|
366
366
|
app.use(attachFail);
|
|
367
|
-
app.use('/api/
|
|
367
|
+
app.use('/api/bongos', buildScoutingRoutes());
|
|
368
368
|
const server = app.listen(0, '127.0.0.1');
|
|
369
369
|
await new Promise((r) => server.once('listening', r));
|
|
370
370
|
const port = server.address().port;
|
|
@@ -381,7 +381,7 @@ function getScouting(caller, query = '') {
|
|
|
381
381
|
currentCaller = caller;
|
|
382
382
|
calls = [];
|
|
383
383
|
return new Promise((resolve, reject) => {
|
|
384
|
-
const req = http.request({ host: '127.0.0.1', port, method: 'GET', path: `/api/
|
|
384
|
+
const req = http.request({ host: '127.0.0.1', port, method: 'GET', path: `/api/bongos/scouting${query}` }, (res) => {
|
|
385
385
|
const chunks = [];
|
|
386
386
|
res.on('data', (c) => chunks.push(c));
|
|
387
387
|
res.on('end', () => resolve({ status: res.statusCode, text: Buffer.concat(chunks).toString('utf8') }));
|
|
@@ -606,7 +606,7 @@ await t('CALIBRATION: the interpreter refuses what it cannot model, rather than
|
|
|
606
606
|
|
|
607
607
|
await t('/people is the SAME endpoint, so "absent from /people" is true by construction', async () => {
|
|
608
608
|
const page = fs.readFileSync(path.join(repo, 'modules/hall-ui/public/people.js'), 'utf8');
|
|
609
|
-
assert.match(page, /fetch\('\/api\/
|
|
609
|
+
assert.match(page, /fetch\('\/api\/bongos\/scouting/,
|
|
610
610
|
'the hall directory reads GET /scouting; if it ever grows its own query, this proof stops covering it');
|
|
611
611
|
const source = fs.readFileSync(path.join(repo, 'modules/platform-identity/platform-identity.js'), 'utf8');
|
|
612
612
|
assert.match(source, /scoutingListableSql\('pa'\)/,
|