@bongos/core 1.24.21 → 1.24.23
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 +25 -25
- package/clients/bongos-client/index.d.ts +1 -1
- package/docs/api/openapi.json +3 -0
- package/docs/api-reference.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/onboarding/founding-birth.js +5 -2
- package/modules/onboarding/founding-mode.js +10 -0
- package/modules/onboarding/genesis-home.js +3 -0
- package/modules/provisioning/birth.js +11 -2
- package/modules/provisioning/routes/provisioning.js +4 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/src/branding.js +3 -0
- package/src/module-api.js +1 -1
- package/tests/founding_birth.mjs +52 -12
- package/tests/founding_mode.mjs +5 -5
- package/tests/genesis_home.mjs +1 -1
- package/tests/provision_settings_apply.mjs +2 -1
- package/tests/provisioning_settings_env.mjs +7 -3
- package/tests/wizard_demo.mjs +5 -2
package/.bongos-core.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/bongos/package-core.js",
|
|
5
|
-
"core_version": "1.24.
|
|
6
|
-
"core_contract": "1.24.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.24.23",
|
|
6
|
+
"core_contract": "1.24.23",
|
|
7
|
+
"source_commit": "1c3eeccc81e91b49ceb762dbe0f15c50db48d4c5",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-11-
|
|
9
|
+
"built_at": "2026-11-02T01:03:41.659Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 632,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 4468,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "08764542a326ca67a7bd4cb22c5eb65f3d618c7e0bee04031fe0c4b3bfe6f77d",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -352,7 +352,7 @@
|
|
|
352
352
|
{
|
|
353
353
|
"path": "clients/bongos-client/index.d.ts",
|
|
354
354
|
"mode": "0000644",
|
|
355
|
-
"sha256": "
|
|
355
|
+
"sha256": "3c301345609619337a39f6385a735722d54552a8e2c4496bc1ab923cd9a65ca5"
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"path": "clients/bongos-client/index.mjs",
|
|
@@ -2457,12 +2457,12 @@
|
|
|
2457
2457
|
{
|
|
2458
2458
|
"path": "docs/api-reference.md",
|
|
2459
2459
|
"mode": "0000644",
|
|
2460
|
-
"sha256": "
|
|
2460
|
+
"sha256": "391006a66d14634cfdc2333d95a9e4aab90376f679b6d4e5b9ff58cd33cec51f"
|
|
2461
2461
|
},
|
|
2462
2462
|
{
|
|
2463
2463
|
"path": "docs/api/openapi.json",
|
|
2464
2464
|
"mode": "0000644",
|
|
2465
|
-
"sha256": "
|
|
2465
|
+
"sha256": "a143477b8f8b9bb1facc61bd0c79f638981c498da2cd04b58997a2cc112df1d8"
|
|
2466
2466
|
},
|
|
2467
2467
|
{
|
|
2468
2468
|
"path": "docs/architecture.md",
|
|
@@ -3002,7 +3002,7 @@
|
|
|
3002
3002
|
{
|
|
3003
3003
|
"path": "docs/module-api-changelog.md",
|
|
3004
3004
|
"mode": "0000644",
|
|
3005
|
-
"sha256": "
|
|
3005
|
+
"sha256": "afa5a90dd4c0277bf47e5f4c9be826088e1e03f533ba548db0ab46f40629d829"
|
|
3006
3006
|
},
|
|
3007
3007
|
{
|
|
3008
3008
|
"path": "docs/modules-contract.md",
|
|
@@ -8802,7 +8802,7 @@
|
|
|
8802
8802
|
{
|
|
8803
8803
|
"path": "modules/onboarding/founding-birth.js",
|
|
8804
8804
|
"mode": "0000644",
|
|
8805
|
-
"sha256": "
|
|
8805
|
+
"sha256": "af17a3f63c31e32ccd863a4ce0a6622673642fa1119796c4b555b8b2696bad94"
|
|
8806
8806
|
},
|
|
8807
8807
|
{
|
|
8808
8808
|
"path": "modules/onboarding/founding-builders.js",
|
|
@@ -8812,12 +8812,12 @@
|
|
|
8812
8812
|
{
|
|
8813
8813
|
"path": "modules/onboarding/founding-mode.js",
|
|
8814
8814
|
"mode": "0000644",
|
|
8815
|
-
"sha256": "
|
|
8815
|
+
"sha256": "9fd376d97133479cebf4c8f8e26696b44c238cead34df335b8c1aa0b4af107e1"
|
|
8816
8816
|
},
|
|
8817
8817
|
{
|
|
8818
8818
|
"path": "modules/onboarding/genesis-home.js",
|
|
8819
8819
|
"mode": "0000644",
|
|
8820
|
-
"sha256": "
|
|
8820
|
+
"sha256": "79a712a6dc1ed7633f25b9558ddca0ca75ee5eba0b996dc5a4a57bb57cfc5356"
|
|
8821
8821
|
},
|
|
8822
8822
|
{
|
|
8823
8823
|
"path": "modules/onboarding/howto-guide.js",
|
|
@@ -9417,7 +9417,7 @@
|
|
|
9417
9417
|
{
|
|
9418
9418
|
"path": "modules/provisioning/birth.js",
|
|
9419
9419
|
"mode": "0000644",
|
|
9420
|
-
"sha256": "
|
|
9420
|
+
"sha256": "e148bfa6918bf5b6a805d6323de91ab99ab81d9c2a796747e17d31dde2db72a2"
|
|
9421
9421
|
},
|
|
9422
9422
|
{
|
|
9423
9423
|
"path": "modules/provisioning/capacity-gate.js",
|
|
@@ -9817,7 +9817,7 @@
|
|
|
9817
9817
|
{
|
|
9818
9818
|
"path": "modules/provisioning/routes/provisioning.js",
|
|
9819
9819
|
"mode": "0000644",
|
|
9820
|
-
"sha256": "
|
|
9820
|
+
"sha256": "c72d11bef0a5fd0f8bbf070dbc28152caac1b1babbdfc9de101172c4fc99d33d"
|
|
9821
9821
|
},
|
|
9822
9822
|
{
|
|
9823
9823
|
"path": "modules/provisioning/routes/render-standup.js",
|
|
@@ -11697,12 +11697,12 @@
|
|
|
11697
11697
|
{
|
|
11698
11698
|
"path": "package-lock.json",
|
|
11699
11699
|
"mode": "0000644",
|
|
11700
|
-
"sha256": "
|
|
11700
|
+
"sha256": "419d4d1ad165101fd9a1017dfc7dbef2905e54d2374ca0c751bfc13f9f14bf7e"
|
|
11701
11701
|
},
|
|
11702
11702
|
{
|
|
11703
11703
|
"path": "package.json",
|
|
11704
11704
|
"mode": "0000644",
|
|
11705
|
-
"sha256": "
|
|
11705
|
+
"sha256": "bb1cca3496a3ea2dcc2422d08c342a7afcf7023eebee2f176e51fd8884514bb4"
|
|
11706
11706
|
},
|
|
11707
11707
|
{
|
|
11708
11708
|
"path": "public-docs/index.html",
|
|
@@ -11722,7 +11722,7 @@
|
|
|
11722
11722
|
{
|
|
11723
11723
|
"path": "release-notes.json",
|
|
11724
11724
|
"mode": "0000644",
|
|
11725
|
-
"sha256": "
|
|
11725
|
+
"sha256": "d027a083157c960a3a8825087b912dc021de55417f406bbed603c3907e352c32"
|
|
11726
11726
|
},
|
|
11727
11727
|
{
|
|
11728
11728
|
"path": "scripts/bongos/CLAUDE.md",
|
|
@@ -15567,7 +15567,7 @@
|
|
|
15567
15567
|
{
|
|
15568
15568
|
"path": "src/branding.js",
|
|
15569
15569
|
"mode": "0000644",
|
|
15570
|
-
"sha256": "
|
|
15570
|
+
"sha256": "8bb8aebce8394eedabcbdf4d11fc5f190b7e03d2ef8b7d902d80d530f117a35f"
|
|
15571
15571
|
},
|
|
15572
15572
|
{
|
|
15573
15573
|
"path": "src/build-info.js",
|
|
@@ -15592,7 +15592,7 @@
|
|
|
15592
15592
|
{
|
|
15593
15593
|
"path": "src/module-api.js",
|
|
15594
15594
|
"mode": "0000644",
|
|
15595
|
-
"sha256": "
|
|
15595
|
+
"sha256": "acfad6615c99259d2b6ffc0d3ed7f23f83a527f5d281937e236378f913c4a8a5"
|
|
15596
15596
|
},
|
|
15597
15597
|
{
|
|
15598
15598
|
"path": "src/module-loader/catalog.js",
|
|
@@ -17457,7 +17457,7 @@
|
|
|
17457
17457
|
{
|
|
17458
17458
|
"path": "tests/founding_birth.mjs",
|
|
17459
17459
|
"mode": "0000644",
|
|
17460
|
-
"sha256": "
|
|
17460
|
+
"sha256": "0a5bcb5742bf1d2fc5fbbd03180f8542ce1557b4616783ba3751cf6ba43abd8e"
|
|
17461
17461
|
},
|
|
17462
17462
|
{
|
|
17463
17463
|
"path": "tests/founding_builders.mjs",
|
|
@@ -17467,7 +17467,7 @@
|
|
|
17467
17467
|
{
|
|
17468
17468
|
"path": "tests/founding_mode.mjs",
|
|
17469
17469
|
"mode": "0000644",
|
|
17470
|
-
"sha256": "
|
|
17470
|
+
"sha256": "76b3892dc8e9811f454778a997dbe3930a991524b0929f89f608d9fba38d80f7"
|
|
17471
17471
|
},
|
|
17472
17472
|
{
|
|
17473
17473
|
"path": "tests/gating_review_retired.mjs",
|
|
@@ -17487,7 +17487,7 @@
|
|
|
17487
17487
|
{
|
|
17488
17488
|
"path": "tests/genesis_home.mjs",
|
|
17489
17489
|
"mode": "0000644",
|
|
17490
|
-
"sha256": "
|
|
17490
|
+
"sha256": "6cadbdc1c3e1a276f2d381f7256d483fda6e07d8cfab1d7ac89837f2b0d64ffd"
|
|
17491
17491
|
},
|
|
17492
17492
|
{
|
|
17493
17493
|
"path": "tests/genesis_life_plates.mjs",
|
|
@@ -20522,7 +20522,7 @@
|
|
|
20522
20522
|
{
|
|
20523
20523
|
"path": "tests/provision_settings_apply.mjs",
|
|
20524
20524
|
"mode": "0000644",
|
|
20525
|
-
"sha256": "
|
|
20525
|
+
"sha256": "cc5a5c1eabf6bf4ebbda9726798393114c543b49d5df533a8e3c6f9d0c800295"
|
|
20526
20526
|
},
|
|
20527
20527
|
{
|
|
20528
20528
|
"path": "tests/provision_teardown_address.mjs",
|
|
@@ -20677,7 +20677,7 @@
|
|
|
20677
20677
|
{
|
|
20678
20678
|
"path": "tests/provisioning_settings_env.mjs",
|
|
20679
20679
|
"mode": "0000644",
|
|
20680
|
-
"sha256": "
|
|
20680
|
+
"sha256": "26c91fde2113a2dff3dd5b9d14ab3609839f69b1f27b768b5028ddee003c737a"
|
|
20681
20681
|
},
|
|
20682
20682
|
{
|
|
20683
20683
|
"path": "tests/provisioning_slug_available.mjs",
|
|
@@ -22267,7 +22267,7 @@
|
|
|
22267
22267
|
{
|
|
22268
22268
|
"path": "tests/wizard_demo.mjs",
|
|
22269
22269
|
"mode": "0000644",
|
|
22270
|
-
"sha256": "
|
|
22270
|
+
"sha256": "d65fcde85566b1cd0d9ded2c267273d6b8717595348c92953803f54485e04c49"
|
|
22271
22271
|
},
|
|
22272
22272
|
{
|
|
22273
22273
|
"path": "tests/wizard_draft_resume.mjs",
|
|
@@ -577,7 +577,7 @@ export interface PostProvisioningInstancesIdRenderResponse { ok: boolean; queued
|
|
|
577
577
|
export interface PostProvisioningInstancesIdRepoPrivateResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; message: unknown }
|
|
578
578
|
export interface PostProvisioningInstancesIdRestartResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; message: unknown }
|
|
579
579
|
export interface PostProvisioningInstancesIdTeardownResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; superseded: unknown; message: unknown }
|
|
580
|
-
export interface PostProvisioningInstancesRequest { slug: string; target_ref?: string; hosting_shape?: string; domain?: string; no_address?: boolean; tier?: string; onboard_mode?: string; type?: string; description?: string; detail?: Record<string, unknown>; modules?: string[]; terms_acknowledged?: boolean; demo?: Record<string, unknown>; ship_mode?: "auto" | "manual" }
|
|
580
|
+
export interface PostProvisioningInstancesRequest { slug: string; target_ref?: string; hosting_shape?: string; domain?: string; no_address?: boolean; tier?: string; onboard_mode?: string; type?: string; description?: string; detail?: Record<string, unknown>; modules?: string[]; terms_acknowledged?: boolean; demo?: Record<string, unknown>; ship_mode?: "auto" | "manual"; genesis?: boolean }
|
|
581
581
|
export interface PostProvisioningPhysicsCheckRequest { description?: string; detail?: Record<string, unknown> }
|
|
582
582
|
export interface PostProvisioningPhysicsCheckResponse { stop: boolean; message: unknown; soft_limits: unknown }
|
|
583
583
|
export interface PostProvisioningRenderLookupRequest { key: string; owner_id?: string }
|
package/docs/api/openapi.json
CHANGED
|
@@ -39404,6 +39404,9 @@
|
|
|
39404
39404
|
"auto",
|
|
39405
39405
|
"manual"
|
|
39406
39406
|
]
|
|
39407
|
+
},
|
|
39408
|
+
"genesis": {
|
|
39409
|
+
"type": "boolean"
|
|
39407
39410
|
}
|
|
39408
39411
|
},
|
|
39409
39412
|
"required": [
|
package/docs/api-reference.md
CHANGED
|
@@ -789,7 +789,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
|
|
|
789
789
|
| GET | `/api/bongos/provisioning/github-app/status` | `public` | — | GET /provisioning/github-app/status?state=<> — the PUBLIC progress read (task 1004548; the checklist since task 1004649). |
|
|
790
790
|
| GET | `/api/bongos/provisioning/health` | `public` | — | GET /provisioning/health — liveness + the core version this module mounted against. |
|
|
791
791
|
| GET | `/api/bongos/provisioning/instances` | `any-builder` | — | GET /provisioning/instances — the caller's own instances + each open intent. |
|
|
792
|
-
| POST | `/api/bongos/provisioning/instances` | `any-builder` | `slug`, `target_ref`, `hosting_shape`, `domain`, `no_address`, `tier`, `onboard_mode`, `type`, `description`, `detail`, `modules`, `terms_acknowledged`, `demo`, `ship_mode` | POST /provisioning/instances — request a new instance. |
|
|
792
|
+
| POST | `/api/bongos/provisioning/instances` | `any-builder` | `slug`, `target_ref`, `hosting_shape`, `domain`, `no_address`, `tier`, `onboard_mode`, `type`, `description`, `detail`, `modules`, `terms_acknowledged`, `demo`, `ship_mode`, `genesis` | POST /provisioning/instances — request a new instance. |
|
|
793
793
|
| GET | `/api/bongos/provisioning/instances/:id` | `any-builder` | — | GET /provisioning/instances/:id — read one instance (the manage page's read). |
|
|
794
794
|
| GET | `/api/bongos/provisioning/instances/:id/core-upgrade` | `archon` | — | GET the same path — step ONE of the two-step (ADR 0293 D4): what a move would do. |
|
|
795
795
|
| POST | `/api/bongos/provisioning/instances/:id/core-upgrade` | `archon` | — | POST /provisioning/instances/:id/core-upgrade — move the core pin. |
|
|
@@ -3298,5 +3298,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
3298
3298
|
landed since 1.24.19 with no explicit bump. run 41141610027. (task 1002620)
|
|
3299
3299
|
1.24.21 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3300
3300
|
landed since 1.24.20 with no explicit bump. run 41364831803. (task 1002620)
|
|
3301
|
+
1.24.22 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3302
|
+
landed since 1.24.21 with no explicit bump. run 41366737579. (task 1002620)
|
|
3303
|
+
1.24.23 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3304
|
+
landed since 1.24.22 with no explicit bump. run 41370306880. (task 1002620)
|
|
3301
3305
|
---------------------------------------------------------------------------
|
|
3302
3306
|
```
|
|
@@ -50,11 +50,13 @@ const { DEMO_PEOPLE, DEMO_HOURS, intIn } = genesis;
|
|
|
50
50
|
function birthMarker(founding) {
|
|
51
51
|
const f = founding && typeof founding === 'object' ? founding : {};
|
|
52
52
|
const born = typeof f.birth === 'string' && Number.isFinite(new Date(f.birth).getTime());
|
|
53
|
-
if (!born) return { born: false, demo: null };
|
|
53
|
+
if (!born) return { born: false, demo: null, genesis: false };
|
|
54
54
|
const people = Number(f.demoPeople);
|
|
55
55
|
const hours = Number(f.demoHours);
|
|
56
56
|
const demo = intIn(people, DEMO_PEOPLE[0], DEMO_PEOPLE[1]) && intIn(hours, DEMO_HOURS[0], DEMO_HOURS[1]) ? { people, hours_each: hours } : null;
|
|
57
|
-
|
|
57
|
+
// Genesis is paused (owner, 2026-11-01): only a birth stamped with the genesis companion starts it, so a
|
|
58
|
+
// project born before the pause, carrying a marker alone, never does.
|
|
59
|
+
return { born: true, demo, genesis: f.genesis === 'on' };
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
function markerFrom(deps) {
|
|
@@ -71,6 +73,7 @@ function markerFrom(deps) {
|
|
|
71
73
|
async function bornFounding(deps = {}) {
|
|
72
74
|
const marker = markerFrom(deps);
|
|
73
75
|
if (!marker.born) return { ran: false, reason: 'no_marker' };
|
|
76
|
+
if (!marker.genesis) return { ran: false, reason: 'genesis_paused' };
|
|
74
77
|
const get = deps.getSetting || require('../../src/module-api').projectSettings.get;
|
|
75
78
|
const [started, ended] = await Promise.all([get(fm.KEYS.STARTED_AT), get(fm.KEYS.ENDED_AT)]);
|
|
76
79
|
if (ended && ended.value) return { ran: false, reason: 'already_alive' };
|
|
@@ -50,6 +50,11 @@ const KEYS = Object.freeze({
|
|
|
50
50
|
// When the planet came alive (founding switched off). With STARTED_AT it bounds the
|
|
51
51
|
// window a builder must have joined in to carry the founding mark (task 1004424).
|
|
52
52
|
ENDED_AT: 'founding.ended_at',
|
|
53
|
+
// Genesis is OFF unless a project turns it on (owner, 2026-11-01: not polished enough, so every
|
|
54
|
+
// project opens as the full hall). Read as ordinary 'true'; absent or anything else is OFF, which is
|
|
55
|
+
// also what pauses a project that was already mid-founding. A demo, or a project born with genesis,
|
|
56
|
+
// turns it on once at birth (founding-birth.js); the owner's own switch can follow it.
|
|
57
|
+
ENABLED: 'genesis.enabled',
|
|
53
58
|
});
|
|
54
59
|
|
|
55
60
|
// The key that records when a stage first became current, so a builder's join time
|
|
@@ -121,6 +126,11 @@ async function foundingModeFor(deps = {}) {
|
|
|
121
126
|
const get = deps.getSetting || require('../../src/module-api').projectSettings.get;
|
|
122
127
|
let shaped;
|
|
123
128
|
try {
|
|
129
|
+
// Paused unless the project turned genesis on: the hall opens full, whatever founding.active says.
|
|
130
|
+
// Asked FIRST and alone, because this is the answer for nearly every project and every /me, so the
|
|
131
|
+
// common case is one read, not four.
|
|
132
|
+
const enabled = await get(KEYS.ENABLED);
|
|
133
|
+
if (!parseActive(enabled && enabled.value)) return null;
|
|
124
134
|
const [active, stage, startedAt] = await Promise.all([
|
|
125
135
|
get(KEYS.ACTIVE), get(KEYS.STAGE), get(KEYS.STARTED_AT),
|
|
126
136
|
]);
|
|
@@ -264,6 +264,9 @@ async function startFounding(builderId, deps = {}) {
|
|
|
264
264
|
const s = seams(deps);
|
|
265
265
|
const ended = await s.get(fm.KEYS.ENDED_AT);
|
|
266
266
|
if (ended && ended.value) return { ok: false, reason: 'already_alive' };
|
|
267
|
+
// Genesis is off unless a project turns it on (task 1005035): starting it IS turning it on, whether the
|
|
268
|
+
// birth does it or the owner's own start route does, so the mode read below never answers null for it.
|
|
269
|
+
await s.set(fm.KEYS.ENABLED, 'true', builderId);
|
|
267
270
|
const mode = await fm.setFoundingMode({ active: true }, builderId, modeDeps(s));
|
|
268
271
|
return { ok: true, mode };
|
|
269
272
|
}
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
// that came and went would leave a stale line behind.
|
|
22
22
|
|
|
23
23
|
const BIRTH_KEY = 'founding_birth';
|
|
24
|
+
// Genesis is paused (owner, 2026-11-01): only a birth stamped with this key starts it. Reserved like the
|
|
25
|
+
// birth itself; a row born before the pause carries the birth alone, so it never founds.
|
|
26
|
+
const GENESIS_KEY = 'founding_genesis';
|
|
24
27
|
// The wizard's ship-mode answer (task 1004629): auto | manual, stamped beside the birth on
|
|
25
28
|
// the row the create route just made. Reserved like the birth (out of SETTINGS_VOCAB): the
|
|
26
29
|
// instance's own project_settings['ship.mode'] is where the setting LIVES and where the
|
|
@@ -36,6 +39,11 @@ function bornAt(row) {
|
|
|
36
39
|
return ISO.test(v) && Number.isFinite(new Date(v).getTime()) ? v : '';
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
// genesisOn(row) — PURE. 'on' only for a born row stamped with genesis, else ''.
|
|
43
|
+
function genesisOn(row) {
|
|
44
|
+
return bornAt(row) && storedOf(row)[GENESIS_KEY] === 'on' ? 'on' : '';
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
// demoBox(row) — PURE. A born demo's { people, hours_each }, or null. Only a row that is
|
|
40
48
|
// both born and a demo carries one: an older demo has no marker and founds nothing.
|
|
41
49
|
function demoBox(row) {
|
|
@@ -57,6 +65,7 @@ const bornShipMode = (row) => parseShipMode(storedOf(row)[SHIP_MODE_KEY]).mode |
|
|
|
57
65
|
// The companion env (SETTINGS_COMPANION_ENV). src/branding.js maps them onto founding.*.
|
|
58
66
|
const BIRTH_COMPANION_ENV = Object.freeze({
|
|
59
67
|
FOUNDING_BIRTH: bornAt,
|
|
68
|
+
FOUNDING_GENESIS: genesisOn,
|
|
60
69
|
DEMO_PEOPLE: (row) => { const d = demoBox(row); return d ? String(d.people) : ''; },
|
|
61
70
|
DEMO_HOURS: (row) => { const d = demoBox(row); return d ? String(d.hours_each) : ''; },
|
|
62
71
|
SHIP_MODE: bornShipMode,
|
|
@@ -67,9 +76,9 @@ const BIRTH_COMPANION_ENV = Object.freeze({
|
|
|
67
76
|
async function stampBirth(db, instanceId, now = new Date()) {
|
|
68
77
|
await db.query(
|
|
69
78
|
`UPDATE provisioning_instances
|
|
70
|
-
SET settings = COALESCE(settings, '{}'::jsonb) || jsonb_build_object($2::text, $3::text)
|
|
79
|
+
SET settings = COALESCE(settings, '{}'::jsonb) || jsonb_build_object($2::text, $3::text, $4::text, 'on')
|
|
71
80
|
WHERE id = $1 AND NOT (COALESCE(settings, '{}'::jsonb) ? $2::text)`,
|
|
72
|
-
[instanceId, BIRTH_KEY, now.toISOString()],
|
|
81
|
+
[instanceId, BIRTH_KEY, now.toISOString(), GENESIS_KEY],
|
|
73
82
|
);
|
|
74
83
|
}
|
|
75
84
|
|
|
@@ -357,7 +357,7 @@ module.exports = function provisioningRoutes() {
|
|
|
357
357
|
// exactly the set the panel preselected. An explicit [] is the different
|
|
358
358
|
// answer "none of them". maxItems is a sanity ceiling well above a catalog
|
|
359
359
|
// that is three modules wide today.
|
|
360
|
-
modules: { type: 'array', itemsType: 'string', maxItems: 50 }, terms_acknowledged: { type: 'boolean' }, demo: { type: 'object' }, ship_mode: { type: 'string', enum: ['auto', 'manual'] }, // the wizard's terms tick (task 1004417, ../terms-ack.js); the demo route's { people, hours_each } (task 1004420, ../demo.js)
|
|
360
|
+
modules: { type: 'array', itemsType: 'string', maxItems: 50 }, terms_acknowledged: { type: 'boolean' }, demo: { type: 'object' }, ship_mode: { type: 'string', enum: ['auto', 'manual'] }, genesis: { type: 'boolean' }, // the wizard's terms tick (task 1004417, ../terms-ack.js); the demo route's { people, hours_each } (task 1004420, ../demo.js)
|
|
361
361
|
})) return;
|
|
362
362
|
const body = req.body || {};
|
|
363
363
|
const detailFault = badProjectDetail(body.detail);
|
|
@@ -472,7 +472,9 @@ module.exports = function provisioningRoutes() {
|
|
|
472
472
|
// Born into genesis (task 1004506, ../birth.js): only the row this request MADE, and before the
|
|
473
473
|
// provision intent exists, so the runner's web.env already carries the marker and the demo's box.
|
|
474
474
|
// Best-effort: a project that misses its marker opens as an ordinary hall; the create still stands.
|
|
475
|
-
|
|
475
|
+
// Genesis is OFF by default (owner, 2026-11-01): a new project opens as the full hall. Only a demo (its
|
|
476
|
+
// time box lives on the birth marker) or an explicit `genesis: true` (the test toggle) is born into it.
|
|
477
|
+
if (created && (demoAsk.demo || body.genesis === true)) await birth.stampBirth(pool, instance.id).catch((err) => log.error('[provisioning] birth marker not stamped', err));
|
|
476
478
|
// The wizard's ship mode (task 1004629) rides beside it; a miss means the project asks at its first ship.
|
|
477
479
|
if (created) await birth.stampShipMode(pool, instance.id, body.ship_mode).catch((err) => log.error('[provisioning] ship mode not stamped', err));
|
|
478
480
|
const demoRow = created && demoAsk.demo ? await demo.startDemoProject(pool, provisioning, instance.id, demoAsk.demo) : null;
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.23",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.24.
|
|
9
|
+
"version": "1.24.23",
|
|
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.24.
|
|
3
|
+
"version": "1.24.23",
|
|
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",
|
package/release-notes.json
CHANGED
|
@@ -11015,5 +11015,17 @@
|
|
|
11015
11015
|
"id": "1005013",
|
|
11016
11016
|
"text": "Every card in the city now says what it is. Under each question sits a short plain explanation: what kind of thing it is, which goal, task, person or module it belongs to, and what answering does. A Review card used to show a"
|
|
11017
11017
|
}
|
|
11018
|
+
],
|
|
11019
|
+
"1.24.22": [
|
|
11020
|
+
{
|
|
11021
|
+
"id": "1005034",
|
|
11022
|
+
"text": "New projects now open as the full hall instead of starting in the guided setup (genesis and founding mode). The guided setup is paused for now and stays available for demo projects and for test projects that ask for it. Projec"
|
|
11023
|
+
}
|
|
11024
|
+
],
|
|
11025
|
+
"1.24.23": [
|
|
11026
|
+
{
|
|
11027
|
+
"id": "1005035",
|
|
11028
|
+
"text": "Projects that were still in the guided setup now open as the full project instead, and no project starts the guided setup unless it is switched on for that project. Hosted projects pick this up when their version is moved forw"
|
|
11029
|
+
}
|
|
11018
11030
|
]
|
|
11019
11031
|
}
|
package/src/branding.js
CHANGED
|
@@ -101,6 +101,9 @@ const ENV_OVERRIDES = [
|
|
|
101
101
|
// start genesis (modules/onboarding/founding-birth.js). SERVER-ONLY: clientBranding
|
|
102
102
|
// publishes no `founding` block.
|
|
103
103
|
['FOUNDING_BIRTH', ['founding', 'birth']],
|
|
104
|
+
// FOUNDING_GENESIS is 'on' only when the platform stamped the birth with genesis (a demo, or a
|
|
105
|
+
// test project asking for it); empty on every project born before the pause.
|
|
106
|
+
['FOUNDING_GENESIS', ['founding', 'genesis']],
|
|
104
107
|
['DEMO_PEOPLE', ['founding', 'demoPeople']],
|
|
105
108
|
['DEMO_HOURS', ['founding', 'demoHours']],
|
|
106
109
|
// The ship mode the founder picked in the wizard (task 1004629), empty when none was.
|
package/src/module-api.js
CHANGED
|
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
|
|
|
81
81
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
82
82
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
83
83
|
|
|
84
|
-
const CORE_VERSION = '1.24.
|
|
84
|
+
const CORE_VERSION = '1.24.23'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
85
85
|
|
|
86
86
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
87
87
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
package/tests/founding_birth.mjs
CHANGED
|
@@ -21,8 +21,8 @@ const birth = require('../modules/onboarding/founding-birth.js');
|
|
|
21
21
|
const gh = require('../modules/onboarding/genesis-home.js');
|
|
22
22
|
const fm = require('../modules/onboarding/founding-mode.js');
|
|
23
23
|
|
|
24
|
-
const BORN = { born: true, demo: null };
|
|
25
|
-
const BORN_DEMO = { born: true, demo: { people: 3, hours_each: 4 } };
|
|
24
|
+
const BORN = { born: true, demo: null, genesis: true };
|
|
25
|
+
const BORN_DEMO = { born: true, demo: { people: 3, hours_each: 4 }, genesis: true };
|
|
26
26
|
|
|
27
27
|
function world({ marker = BORN, settings = {}, withLifecycle = true } = {}) {
|
|
28
28
|
const store = new Map(Object.entries(settings));
|
|
@@ -43,19 +43,59 @@ function world({ marker = BORN, settings = {}, withLifecycle = true } = {}) {
|
|
|
43
43
|
|
|
44
44
|
// ── the marker ───────────────────────────────────────────────────────────────
|
|
45
45
|
|
|
46
|
-
test('the marker: born only with a readable birth stamp; a demo box only inside its limits', () => {
|
|
47
|
-
|
|
48
|
-
assert.deepEqual(birth.birthMarker(
|
|
49
|
-
assert.deepEqual(birth.birthMarker({
|
|
50
|
-
assert.deepEqual(birth.birthMarker({ birth: '
|
|
51
|
-
assert.deepEqual(birth.birthMarker({ birth:
|
|
52
|
-
|
|
53
|
-
assert.deepEqual(birth.birthMarker({ birth:
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
test('the marker: born only with a readable birth stamp; a demo box only inside its limits; genesis only when stamped', () => {
|
|
47
|
+
const AT = '2026-10-01T00:00:00.000Z';
|
|
48
|
+
assert.deepEqual(birth.birthMarker(undefined), { born: false, demo: null, genesis: false });
|
|
49
|
+
assert.deepEqual(birth.birthMarker({}), { born: false, demo: null, genesis: false });
|
|
50
|
+
assert.deepEqual(birth.birthMarker({ birth: 'whenever' }), { born: false, demo: null, genesis: false });
|
|
51
|
+
assert.deepEqual(birth.birthMarker({ birth: AT }), { born: true, demo: null, genesis: false }, 'a birth alone (every project born before the pause) never founds');
|
|
52
|
+
assert.deepEqual(birth.birthMarker({ birth: AT, genesis: 'on' }), { born: true, demo: null, genesis: true });
|
|
53
|
+
assert.deepEqual(birth.birthMarker({ birth: AT, genesis: 'yes' }), { born: true, demo: null, genesis: false }, 'only the stamped spelling counts');
|
|
54
|
+
assert.deepEqual(birth.birthMarker({ birth: AT, genesis: 'on', demoPeople: '3', demoHours: '4' }),
|
|
55
|
+
{ born: true, demo: { people: 3, hours_each: 4 }, genesis: true });
|
|
56
|
+
assert.deepEqual(birth.birthMarker({ birth: AT, genesis: 'on', demoPeople: '99', demoHours: '4' }),
|
|
57
|
+
{ born: true, demo: null, genesis: true }, 'a malformed box still founds, with the ordinary plan');
|
|
58
|
+
assert.deepEqual(birth.birthMarker({ demoPeople: '3', demoHours: '4' }), { born: false, demo: null, genesis: false },
|
|
56
59
|
'a demo box without a birth is not a birth');
|
|
57
60
|
});
|
|
58
61
|
|
|
62
|
+
test('genesis is paused: a birth without the genesis stamp starts nothing and writes nothing', async () => {
|
|
63
|
+
const w = world({ marker: { born: true, demo: null, genesis: false } });
|
|
64
|
+
const r = await birth.bornFounding(w.deps());
|
|
65
|
+
assert.deepEqual(r, { ran: false, reason: 'genesis_paused' });
|
|
66
|
+
assert.deepEqual(w.writes, [], 'no setting is touched');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('the switch: founding.active alone reads as not founding; the switch makes it read', async () => {
|
|
70
|
+
const store = new Map([[fm.KEYS.ACTIVE, 'true'], [fm.KEYS.STAGE, 'charter']]);
|
|
71
|
+
const getSetting = async (k) => (store.has(k) ? { key: k, value: store.get(k) } : null);
|
|
72
|
+
assert.equal(await fm.foundingModeFor({ getSetting, government: null }), null, 'a project already mid-founding opens as the full hall');
|
|
73
|
+
store.set(fm.KEYS.ENABLED, 'true');
|
|
74
|
+
assert.equal((await fm.foundingModeFor({ getSetting, government: null })).stage, 'charter');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('an owner starting genesis turns the switch on, so a started genesis is never invisible', async () => {
|
|
78
|
+
const w = world();
|
|
79
|
+
const r = await gh.startFounding('7', w.deps());
|
|
80
|
+
assert.equal(r.ok, true);
|
|
81
|
+
assert.equal(w.store.get(fm.KEYS.ENABLED), 'true');
|
|
82
|
+
assert.equal(r.mode.active, true, 'the mode it answers with reads, not null');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('a paused project costs ONE settings read, not four', async () => {
|
|
86
|
+
let reads = 0;
|
|
87
|
+
const getSetting = async () => { reads += 1; return null; };
|
|
88
|
+
assert.equal(await fm.foundingModeFor({ getSetting }), null);
|
|
89
|
+
assert.equal(reads, 1, 'the switch is asked first and alone');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('a birth with genesis turns the switch on, once, before founding starts', async () => {
|
|
93
|
+
const w = world();
|
|
94
|
+
await birth.bornFounding(w.deps());
|
|
95
|
+
assert.equal(w.store.get(fm.KEYS.ENABLED), 'true');
|
|
96
|
+
assert.ok(w.writes.indexOf(fm.KEYS.ENABLED) < w.writes.indexOf(fm.KEYS.ACTIVE), 'the switch is on before founding is');
|
|
97
|
+
});
|
|
98
|
+
|
|
59
99
|
// ── the birth hook ───────────────────────────────────────────────────────────
|
|
60
100
|
|
|
61
101
|
test('no marker: nothing runs, and the database is never read (a pre-existing hall is unchanged)', async () => {
|
package/tests/founding_mode.mjs
CHANGED
|
@@ -70,7 +70,7 @@ test('foundingModeFor fails closed when the settings read throws', async () => {
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
test('setFoundingMode refuses an unknown stage and stamps started_at once', async () => {
|
|
73
|
-
const store = new Map();
|
|
73
|
+
const store = new Map([[fm.KEYS.ENABLED, 'true']]);
|
|
74
74
|
const deps = {
|
|
75
75
|
getSetting: async (k) => (store.has(k) ? { key: k, value: store.get(k) } : null),
|
|
76
76
|
setSetting: async (k, v) => { store.set(k, String(v)); return { key: k, value: String(v) }; },
|
|
@@ -227,7 +227,7 @@ test('the band escapes what it prints — a project name cannot inject markup',
|
|
|
227
227
|
|
|
228
228
|
test('who the stage close is waiting on shows in the band when the server sends it', async () => {
|
|
229
229
|
const f = await fm.foundingModeFor({
|
|
230
|
-
getSetting: async (k) => ({ [fm.KEYS.ACTIVE]: { value: 'true' }, [fm.KEYS.STAGE]: { value: 'charter' } }[k] || null),
|
|
230
|
+
getSetting: async (k) => ({ [fm.KEYS.ENABLED]: { value: 'true' }, [fm.KEYS.ACTIVE]: { value: 'true' }, [fm.KEYS.STAGE]: { value: 'charter' } }[k] || null),
|
|
231
231
|
waitingOnFor: async (stage) => (stage === 'charter' ? ['Avery', 'Jordan'] : []),
|
|
232
232
|
});
|
|
233
233
|
assert.deepEqual(f.waiting_on, ['Avery', 'Jordan']);
|
|
@@ -245,20 +245,20 @@ test('waiting-on reads the government port\'s genesis-stage status, sitting stag
|
|
|
245
245
|
] }),
|
|
246
246
|
};
|
|
247
247
|
const read = (stage) => fm.foundingModeFor({
|
|
248
|
-
getSetting: async (k) => ({ [fm.KEYS.ACTIVE]: { value: 'true' }, [fm.KEYS.STAGE]: { value: stage } }[k] || null),
|
|
248
|
+
getSetting: async (k) => ({ [fm.KEYS.ENABLED]: { value: 'true' }, [fm.KEYS.ACTIVE]: { value: 'true' }, [fm.KEYS.STAGE]: { value: stage } }[k] || null),
|
|
249
249
|
government: gov,
|
|
250
250
|
});
|
|
251
251
|
assert.deepEqual((await read('charter')).waiting_on, ['Avery', 'jordan']);
|
|
252
252
|
assert.equal((await read('scope')).waiting_on, null, 'a passed stage waits on nobody');
|
|
253
253
|
assert.equal(fm.waitingOnFromGovernment({}), null, 'a port without the read offers none');
|
|
254
254
|
assert.equal((await fm.foundingModeFor({
|
|
255
|
-
getSetting: async (k) => ({ [fm.KEYS.ACTIVE]: { value: 'true' } }[k] || null), government: null,
|
|
255
|
+
getSetting: async (k) => ({ [fm.KEYS.ENABLED]: { value: 'true' }, [fm.KEYS.ACTIVE]: { value: 'true' } }[k] || null), government: null,
|
|
256
256
|
})).waiting_on, null, 'no government module: the mode still reads, without names');
|
|
257
257
|
});
|
|
258
258
|
|
|
259
259
|
test('a failing waiting-on source never turns the mode off', async () => {
|
|
260
260
|
const f = await fm.foundingModeFor({
|
|
261
|
-
getSetting: async (k) => ({ [fm.KEYS.ACTIVE]: { value: 'true' }, [fm.KEYS.STAGE]: { value: 'scope' } }[k] || null),
|
|
261
|
+
getSetting: async (k) => ({ [fm.KEYS.ENABLED]: { value: 'true' }, [fm.KEYS.ACTIVE]: { value: 'true' }, [fm.KEYS.STAGE]: { value: 'scope' } }[k] || null),
|
|
262
262
|
waitingOnFor: async () => { throw new Error('government down'); },
|
|
263
263
|
});
|
|
264
264
|
assert.equal(f.active, true);
|
package/tests/genesis_home.mjs
CHANGED
|
@@ -146,7 +146,7 @@ test('a demo genesis reads in minutes: each stage due minutes after it began', (
|
|
|
146
146
|
// ── the flow, end to end over fakes ──────────────────────────────────────────
|
|
147
147
|
|
|
148
148
|
function world({ withGovernment = true } = {}) {
|
|
149
|
-
const store = new Map();
|
|
149
|
+
const store = new Map([['genesis.enabled', 'true']]);
|
|
150
150
|
const tasks = {};
|
|
151
151
|
const board = {};
|
|
152
152
|
let now = new Date('2026-10-01T00:00:00Z');
|
|
@@ -76,6 +76,7 @@ ${NEUTRAL_PREFIX}_ARTIST_GATE_SINCE=
|
|
|
76
76
|
${NEUTRAL_PREFIX}_LOOK_ACCENT=
|
|
77
77
|
${NEUTRAL_PREFIX}_LOGO_URL=
|
|
78
78
|
${NEUTRAL_PREFIX}_FOUNDING_BIRTH=
|
|
79
|
+
${NEUTRAL_PREFIX}_FOUNDING_GENESIS=
|
|
79
80
|
${NEUTRAL_PREFIX}_DEMO_PEOPLE=
|
|
80
81
|
${NEUTRAL_PREFIX}_DEMO_HOURS=
|
|
81
82
|
${NEUTRAL_PREFIX}_SHIP_MODE=
|
|
@@ -148,7 +149,7 @@ t('settingsEnvVarsFor: the runner pushes the SAME pair webEnvBody writes at stan
|
|
|
148
149
|
[`${NEUTRAL_PREFIX}_LOOK`]: 'own', [`${NEUTRAL_PREFIX}_NIGHT_TINT`]: 'on',
|
|
149
150
|
[`${NEUTRAL_PREFIX}_LOOK_ACCENT`]: '', [`${NEUTRAL_PREFIX}_LOGO_URL`]: '',
|
|
150
151
|
// the birth marker and a demo's box (task 1004506), empty on an un-stamped row
|
|
151
|
-
[`${NEUTRAL_PREFIX}_FOUNDING_BIRTH`]: '', [`${NEUTRAL_PREFIX}_DEMO_PEOPLE`]: '', [`${NEUTRAL_PREFIX}_DEMO_HOURS`]: '',
|
|
152
|
+
[`${NEUTRAL_PREFIX}_FOUNDING_BIRTH`]: '', [`${NEUTRAL_PREFIX}_FOUNDING_GENESIS`]: '', [`${NEUTRAL_PREFIX}_DEMO_PEOPLE`]: '', [`${NEUTRAL_PREFIX}_DEMO_HOURS`]: '',
|
|
152
153
|
// the wizard's ship mode (task 1004629), empty when none was picked
|
|
153
154
|
[`${NEUTRAL_PREFIX}_SHIP_MODE`]: '',
|
|
154
155
|
// where the hall's Update button goes (task 1004608), empty when no hub origin resolves
|
|
@@ -126,7 +126,7 @@ t('settingsEnvVars is the single source both legs derive from — same keys, sam
|
|
|
126
126
|
CLOUDBONGOS_LOOK: 'own', CLOUDBONGOS_NIGHT_TINT: 'on', CLOUDBONGOS_LOOK_ACCENT: '', CLOUDBONGOS_LOGO_URL: '',
|
|
127
127
|
// The birth marker and a demo's box (task 1004506): empty on a row the create
|
|
128
128
|
// route never stamped, which is every row made before it shipped (spec D8).
|
|
129
|
-
CLOUDBONGOS_FOUNDING_BIRTH: '', CLOUDBONGOS_DEMO_PEOPLE: '', CLOUDBONGOS_DEMO_HOURS: '',
|
|
129
|
+
CLOUDBONGOS_FOUNDING_BIRTH: '', CLOUDBONGOS_FOUNDING_GENESIS: '', CLOUDBONGOS_DEMO_PEOPLE: '', CLOUDBONGOS_DEMO_HOURS: '',
|
|
130
130
|
// The wizard's ship mode (task 1004629): empty when none was picked.
|
|
131
131
|
CLOUDBONGOS_SHIP_MODE: '',
|
|
132
132
|
});
|
|
@@ -137,7 +137,7 @@ t('settingsEnvVars is the single source both legs derive from — same keys, sam
|
|
|
137
137
|
X_PLATFORM_VISIBILITY: 'public', X_JOINABILITY: 'apply', X_VISIBILITY: 'public', X_JOIN_GRANT: 'full',
|
|
138
138
|
X_ARTIST_GATE: 'strict', X_ARTIST_GATE_SINCE: '', X_SPEND_PAYER: 'none',
|
|
139
139
|
X_LOOK: 'own', X_NIGHT_TINT: 'on', X_LOOK_ACCENT: '', X_LOGO_URL: '',
|
|
140
|
-
X_FOUNDING_BIRTH: '', X_DEMO_PEOPLE: '', X_DEMO_HOURS: '', X_SHIP_MODE: '',
|
|
140
|
+
X_FOUNDING_BIRTH: '', X_FOUNDING_GENESIS: '', X_DEMO_PEOPLE: '', X_DEMO_HOURS: '', X_SHIP_MODE: '',
|
|
141
141
|
}, 'defaults, explicitly');
|
|
142
142
|
});
|
|
143
143
|
|
|
@@ -155,6 +155,10 @@ t('a stamped row carries its birth; only a stamped DEMO carries the box', () =>
|
|
|
155
155
|
assert.deepEqual([oldDemo.X_FOUNDING_BIRTH, oldDemo.X_DEMO_PEOPLE, oldDemo.X_DEMO_HOURS], ['', '', ''],
|
|
156
156
|
'a demo made before the birth shipped is not born into anything, box and all');
|
|
157
157
|
assert.equal(provisioning.settingsEnvVars({ settings: { founding_birth: 'yesterday' } }, 'X').X_FOUNDING_BIRTH, '', 'a mangled stamp reads as none');
|
|
158
|
+
// Genesis is paused: only a birth stamped with the genesis key carries the companion (owner, 2026-11-01).
|
|
159
|
+
assert.equal(provisioning.settingsEnvVars({ settings: { founding_birth: at, founding_genesis: 'on' } }, 'X').X_FOUNDING_GENESIS, 'on');
|
|
160
|
+
assert.equal(real.X_FOUNDING_GENESIS, '', 'a birth alone, the shape of every project before the pause, does not found');
|
|
161
|
+
assert.equal(provisioning.settingsEnvVars({ settings: { founding_genesis: 'on' } }, 'X').X_FOUNDING_GENESIS, '', 'the genesis key without a birth is nothing');
|
|
158
162
|
});
|
|
159
163
|
|
|
160
164
|
t('the stamp can neither leak as a setting nor be written by a client patch', () => {
|
|
@@ -172,7 +176,7 @@ t('stampBirth writes the row it is given, once: an existing stamp is kept', () =
|
|
|
172
176
|
assert.equal(seen.length, 1);
|
|
173
177
|
assert.match(seen[0].sql, /UPDATE provisioning_instances/);
|
|
174
178
|
assert.match(seen[0].sql, /WHERE id = \$1 AND NOT \(COALESCE\(settings, '\{\}'::jsonb\) \? \$2::text\)/, 'write-once');
|
|
175
|
-
assert.deepEqual(seen[0].params, [41, BIRTH_KEY, '2026-10-01T00:00:00.000Z']);
|
|
179
|
+
assert.deepEqual(seen[0].params, [41, BIRTH_KEY, '2026-10-01T00:00:00.000Z', 'founding_genesis']);
|
|
176
180
|
});
|
|
177
181
|
|
|
178
182
|
t('the instance reads the marker into founding.*, and never publishes it to the client', () => {
|
package/tests/wizard_demo.mjs
CHANGED
|
@@ -171,7 +171,10 @@ test('a new project is stamped born, once, before its provision intent; an exist
|
|
|
171
171
|
assert.deepEqual(order, ['birth:41', 'demo:41', 'enqueue:provision'], 'the marker and the demo box are on the row before the runner can read it');
|
|
172
172
|
order.length = 0;
|
|
173
173
|
assert.equal((await post('/provisioning/instances', { slug: 'born-real', hosting_shape: 'byo-host' })).status, 201);
|
|
174
|
-
assert.deepEqual(order, ['
|
|
174
|
+
assert.deepEqual(order, ['enqueue:provision'], 'a real project opens as the full hall: genesis is off by default (owner, 2026-11-01)');
|
|
175
|
+
order.length = 0;
|
|
176
|
+
assert.equal((await post('/provisioning/instances', { slug: 'born-test', hosting_shape: 'byo-host', genesis: true })).status, 201);
|
|
177
|
+
assert.deepEqual(order, ['birth:41', 'enqueue:provision'], 'the genesis toggle still births a test project, with no demo box');
|
|
175
178
|
order.length = 0;
|
|
176
179
|
const again = await post('/provisioning/instances', { slug: 'old-one', hosting_shape: 'byo-host' });
|
|
177
180
|
assert.ok(again.status < 300, JSON.stringify(again.body));
|
|
@@ -179,7 +182,7 @@ test('a new project is stamped born, once, before its provision intent; an exist
|
|
|
179
182
|
const keep = birth.stampBirth;
|
|
180
183
|
birth.stampBirth = async () => { throw new Error('db hiccup'); };
|
|
181
184
|
try {
|
|
182
|
-
assert.equal((await post('/provisioning/instances', { slug: 'unlucky', hosting_shape: 'byo-host' })).status, 201,
|
|
185
|
+
assert.equal((await post('/provisioning/instances', { slug: 'unlucky', hosting_shape: 'byo-host', genesis: true })).status, 201,
|
|
183
186
|
'a missed marker costs the project its genesis, never its creation');
|
|
184
187
|
} finally { birth.stampBirth = keep; }
|
|
185
188
|
});
|