@bongos/core 1.19.319 → 1.19.320
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 +121 -36
- package/.claude/skills/merge-mode/SKILL.md +3 -1
- package/.devcontainer/init-firewall.sh +41 -5
- package/clients/bongos-client/examples/hello-world.mjs +11 -2
- package/docs/copy-inventory.md +20 -20
- package/docs/copy-registry.json +22 -22
- package/modules/hall-ui/public/builders.js +0 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/audit-replay.sh +20 -3
- package/scripts/gds/box.js +79 -86
- package/scripts/gds/db-backup-nightly.sh +17 -4
- package/scripts/gds/db-backup-offsite.sh +23 -6
- package/scripts/gds/discipline-modes.json +1 -1
- package/scripts/gds/doc-cli-guard.js +34 -2
- package/scripts/gds/fitness.js +8 -4
- package/scripts/gds/gds-db-backup.service +15 -4
- package/scripts/gds/gds-db-backup.timer +12 -1
- package/scripts/gds/gds-db-offsite.service +16 -5
- package/scripts/gds/gds-db-offsite.timer +12 -1
- package/scripts/gds/instance-apex.js +28 -0
- package/scripts/gds/newcomer-floor.templates.json +2 -2
- package/scripts/gds/provision.js +7 -3
- package/scripts/gds/ship-deploy-target.js +388 -0
- package/scripts/gds/ship-finish.js +377 -0
- package/scripts/gds/ship-flow.js +814 -0
- package/scripts/gds/ship-git.js +100 -0
- package/scripts/gds/ship-grade-steps.js +376 -0
- package/scripts/gds/ship-grade.js +319 -0
- package/scripts/gds/ship-io.js +100 -0
- package/scripts/gds/ship-land.js +539 -0
- package/scripts/gds/ship-memory-sync.js +192 -0
- package/scripts/gds/ship-merge.js +297 -0
- package/scripts/gds/ship-preflight-steps.js +323 -0
- package/scripts/gds/ship-regen.js +286 -0
- package/scripts/gds/ship-resume.js +151 -0
- package/scripts/gds/ship-session-upload.js +216 -0
- package/scripts/gds/ship-state.js +73 -0
- package/scripts/gds/ship-surprise.js +84 -0
- package/scripts/gds/ship.js +105 -4195
- package/scripts/status-probe.mjs +30 -2
- package/src/module-api.js +3 -1
- package/tests/helpers.mjs +13 -0
- package/tests/provision.mjs +7 -1
- package/tests/regrade_eligibility.mjs +43 -0
- package/tests/ship_assurance.mjs +4 -2
- package/tests/ship_publish_error.mjs +43 -0
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
//
|
|
16
16
|
// WHAT IT CHECKS, deliberately narrow: for every `node scripts/gds/<x>.js` in a
|
|
17
17
|
// tracked .md, (a) the script exists, and (b) each `--flag` written next to it
|
|
18
|
-
// appears in that script's source. Nothing else — this is not a prose linter.
|
|
18
|
+
// appears in that script's source (or in a same-directory module it requires — a CLI may be carved into phase files). Nothing else — this is not a prose linter.
|
|
19
19
|
//
|
|
20
20
|
// STATIC ONLY, NEVER EXECUTED. The reason matters: running every documented CLI
|
|
21
21
|
// would be slow, would need a session, and a command that blocks on a prompt
|
|
@@ -203,6 +203,38 @@ const readFileOrNull = (rel) => {
|
|
|
203
203
|
|
|
204
204
|
const NAME = 'a doc that names a CLI matches the real CLI (G01)';
|
|
205
205
|
|
|
206
|
+
// readCliSource — a CLI's source PLUS the source of the same-directory modules
|
|
207
|
+
// it requires, concatenated.
|
|
208
|
+
//
|
|
209
|
+
// A big CLI is allowed to be more than one file: task 1003205 carved
|
|
210
|
+
// scripts/gds/ship.js into ship-*.js phase modules, and the flag parsing for
|
|
211
|
+
// e.g. `--no-surprise` moved with the phase that reads it. Scanning ship.js
|
|
212
|
+
// alone then reports a documented, genuinely-honoured flag as a violation —
|
|
213
|
+
// a false alarm that pushes the next agent toward silencing the rule via
|
|
214
|
+
// DOC_CLI_ALLOW, which is exactly the outcome the rule exists to prevent.
|
|
215
|
+
//
|
|
216
|
+
// One level of same-directory relative requires is enough (it is where a carve
|
|
217
|
+
// puts things) and keeps the read bounded. A missing sibling is skipped: the
|
|
218
|
+
// point is to find the flag, not to prove the require graph.
|
|
219
|
+
function readCliSource(rel) {
|
|
220
|
+
const src = readFileOrNull(rel);
|
|
221
|
+
if (src === null) return null;
|
|
222
|
+
const dir = path.dirname(rel);
|
|
223
|
+
const seen = new Set([rel]);
|
|
224
|
+
const parts = [src];
|
|
225
|
+
const RE = /require\(\s*['"](\.\/[^'"]+)['"]\s*\)/g;
|
|
226
|
+
let m;
|
|
227
|
+
while ((m = RE.exec(src))) {
|
|
228
|
+
let sib = path.join(dir, m[1]);
|
|
229
|
+
if (!sib.endsWith('.js')) sib += '.js';
|
|
230
|
+
if (seen.has(sib)) continue;
|
|
231
|
+
seen.add(sib);
|
|
232
|
+
const sibSrc = readFileOrNull(sib);
|
|
233
|
+
if (sibSrc !== null) parts.push(sibSrc);
|
|
234
|
+
}
|
|
235
|
+
return parts.join('\n');
|
|
236
|
+
}
|
|
237
|
+
|
|
206
238
|
function checkDocNamesRealCli({ files = null } = {}) {
|
|
207
239
|
const docs = files || trackedMarkdown();
|
|
208
240
|
// A lint that reports on nothing is worse than one that fails (the
|
|
@@ -217,7 +249,7 @@ function checkDocNamesRealCli({ files = null } = {}) {
|
|
|
217
249
|
}
|
|
218
250
|
|
|
219
251
|
const { violations, warnings, invocations } = scanDocs(docs, {
|
|
220
|
-
readDoc: readFileOrNull, readScript:
|
|
252
|
+
readDoc: readFileOrNull, readScript: readCliSource,
|
|
221
253
|
});
|
|
222
254
|
|
|
223
255
|
return {
|
package/scripts/gds/fitness.js
CHANGED
|
@@ -1023,9 +1023,14 @@ const IDENTITY_SCAN_ALLOWED = {
|
|
|
1023
1023
|
'scripts/gds/fitness.js': 2,
|
|
1024
1024
|
'scripts/gds/package-core.js': 1,
|
|
1025
1025
|
'scripts/gds/seed-v3-tasks.js': 14,
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1026
|
+
// audit-replay.sh + db-backup-{nightly,offsite}.sh were carved out here as
|
|
1027
|
+
// "host-pinned ops"; task 1002757 RETIRED that justification for them — each
|
|
1028
|
+
// now resolves its database from the branding pack (the migrate.sh pattern) and
|
|
1029
|
+
// fails loudly rather than defaulting, so their counts ratcheted to zero and the
|
|
1030
|
+
// entries are gone. seed-staging.sh keeps its carve-out on the OPPOSITE
|
|
1031
|
+
// rationale: its literal is a fail-CLOSED safety interlock (the script wipes
|
|
1032
|
+
// STAGING_DB and refuses unless the name matches exactly), so on any other
|
|
1033
|
+
// instance it declines to run instead of destroying the wrong database.
|
|
1029
1034
|
'scripts/gds/seed-staging.sh': 4,
|
|
1030
1035
|
'scripts/gds/backfill-sessions.js': 2,
|
|
1031
1036
|
'scripts/gds/box.js': 3,
|
|
@@ -1649,7 +1654,6 @@ function checkWriteRoutesValidated() {
|
|
|
1649
1654
|
};
|
|
1650
1655
|
}
|
|
1651
1656
|
|
|
1652
|
-
|
|
1653
1657
|
// ── Check 19 — the ADR 0174 vocabulary wall (goal 1000068 R07, task 1003008) ──
|
|
1654
1658
|
//
|
|
1655
1659
|
// "Role" means ONE thing in this codebase: a craft — Artist, Ideator, or Builder.
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
+
# TEMPLATE — not installable as-is (task 1002757). The __TOKENS__ below MUST be
|
|
2
|
+
# substituted at install time; a provisioned instance gets a correct per-instance
|
|
3
|
+
# unit pair generated by scripts/gds/provision.js (task 2213) and never needs this
|
|
4
|
+
# file. Substitute:
|
|
5
|
+
# __SERVICE_USER__ the unix user that owns the instance + its Postgres role
|
|
6
|
+
# __INSTANCE_ROOT__ the instance checkout root (docs live under it)
|
|
7
|
+
# __CORE_SCRIPTS_DIR__ the deployed core's scripts/gds dir:
|
|
8
|
+
# standalone: <instance-root>/node_modules/@bongos/core/scripts/gds
|
|
9
|
+
# full clone: <instance-root>/scripts/gds
|
|
10
|
+
# __CONFIG_DIR__ the instance config dir name (offsite unit only)
|
|
11
|
+
# One-liner: sed -e 's|__SERVICE_USER__|<user>|g' -e … gds-db-backup.service | sudo tee /etc/systemd/system/…
|
|
1
12
|
[Unit]
|
|
2
13
|
Description=Nightly pg_dump of GDS Postgres DB (filed by #412)
|
|
3
|
-
Documentation=file
|
|
14
|
+
Documentation=file://__INSTANCE_ROOT__/docs/recipes/gds-db-backup.md
|
|
4
15
|
After=postgresql.service
|
|
5
16
|
Requires=postgresql.service
|
|
6
17
|
|
|
7
18
|
[Service]
|
|
8
19
|
Type=oneshot
|
|
9
|
-
User=
|
|
10
|
-
Group=
|
|
20
|
+
User=__SERVICE_USER__
|
|
21
|
+
Group=__SERVICE_USER__
|
|
11
22
|
# Run the canonical script from the deployed repo. Keep this path stable;
|
|
12
23
|
# the recipe doc points at it for restore + manual-one-shot use cases.
|
|
13
24
|
#
|
|
@@ -25,7 +36,7 @@ Group=lars
|
|
|
25
36
|
# vendored/standalone: /home/<user>/<instance>/node_modules/@bongos/core/scripts/gds/db-backup-nightly.sh
|
|
26
37
|
# full clone: /home/<user>/<repo>/scripts/gds/db-backup-nightly.sh
|
|
27
38
|
# See docs/recipes/gds-db-backup.md.
|
|
28
|
-
ExecStart=/usr/bin/env bash /
|
|
39
|
+
ExecStart=/usr/bin/env bash __CORE_SCRIPTS_DIR__/db-backup-nightly.sh
|
|
29
40
|
# Modest hardening — the script only needs read on the socket + write on
|
|
30
41
|
# /var/backups/gds. Anything else is gravy for forensics.
|
|
31
42
|
NoNewPrivileges=true
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
# TEMPLATE — not installable as-is (task 1002757). The __TOKENS__ below MUST be
|
|
2
|
+
# substituted at install time; a provisioned instance gets a correct per-instance
|
|
3
|
+
# unit pair generated by scripts/gds/provision.js (task 2213) and never needs this
|
|
4
|
+
# file. Substitute:
|
|
5
|
+
# __SERVICE_USER__ the unix user that owns the instance + its Postgres role
|
|
6
|
+
# __INSTANCE_ROOT__ the instance checkout root (docs live under it)
|
|
7
|
+
# __CORE_SCRIPTS_DIR__ the deployed core's scripts/gds dir:
|
|
8
|
+
# standalone: <instance-root>/node_modules/@bongos/core/scripts/gds
|
|
9
|
+
# full clone: <instance-root>/scripts/gds
|
|
10
|
+
# __CONFIG_DIR__ the instance config dir name (offsite unit only)
|
|
11
|
+
# One-liner: sed -e 's|__SERVICE_USER__|<user>|g' -e … gds-db-backup.service | sudo tee /etc/systemd/system/…
|
|
1
12
|
[Unit]
|
|
2
13
|
Description=Daily timer for GDS DB pg_dump (filed by #412)
|
|
3
|
-
Documentation=file
|
|
14
|
+
Documentation=file://__INSTANCE_ROOT__/docs/recipes/gds-db-backup.md
|
|
4
15
|
|
|
5
16
|
[Timer]
|
|
6
17
|
# Run every day at 04:00 UTC. That's a low-traffic window for a
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
+
# TEMPLATE — not installable as-is (task 1002757). The __TOKENS__ below MUST be
|
|
2
|
+
# substituted at install time; a provisioned instance gets a correct per-instance
|
|
3
|
+
# unit pair generated by scripts/gds/provision.js (task 2213) and never needs this
|
|
4
|
+
# file. Substitute:
|
|
5
|
+
# __SERVICE_USER__ the unix user that owns the instance + its Postgres role
|
|
6
|
+
# __INSTANCE_ROOT__ the instance checkout root (docs live under it)
|
|
7
|
+
# __CORE_SCRIPTS_DIR__ the deployed core's scripts/gds dir:
|
|
8
|
+
# standalone: <instance-root>/node_modules/@bongos/core/scripts/gds
|
|
9
|
+
# full clone: <instance-root>/scripts/gds
|
|
10
|
+
# __CONFIG_DIR__ the instance config dir name (offsite unit only)
|
|
11
|
+
# One-liner: sed -e 's|__SERVICE_USER__|<user>|g' -e … gds-db-backup.service | sudo tee /etc/systemd/system/…
|
|
1
12
|
[Unit]
|
|
2
13
|
Description=Weekly offsite archive of GDS Postgres dumps to DigitalOcean Spaces (filed by #415)
|
|
3
|
-
Documentation=file
|
|
14
|
+
Documentation=file://__INSTANCE_ROOT__/docs/recipes/gds-db-backup.md
|
|
4
15
|
After=network-online.target
|
|
5
16
|
Wants=network-online.target
|
|
6
17
|
|
|
7
18
|
[Service]
|
|
8
19
|
Type=oneshot
|
|
9
|
-
User=
|
|
10
|
-
Group=
|
|
20
|
+
User=__SERVICE_USER__
|
|
21
|
+
Group=__SERVICE_USER__
|
|
11
22
|
# Run the canonical script from the deployed repo. Keep this path stable;
|
|
12
23
|
# the recipe doc points at it for restore + manual-one-shot use cases.
|
|
13
24
|
#
|
|
@@ -18,12 +29,12 @@ Group=lars
|
|
|
18
29
|
# this unit would have hit it on its first run.
|
|
19
30
|
#
|
|
20
31
|
# EDIT THIS PATH when installing (layout differs — vendored vs full clone).
|
|
21
|
-
ExecStart=/usr/bin/env bash /
|
|
32
|
+
ExecStart=/usr/bin/env bash __CORE_SCRIPTS_DIR__/db-backup-offsite.sh
|
|
22
33
|
# S3 credentials for the Space live outside the repo (ADR 0022). systemd
|
|
23
34
|
# injects them; the file is chmod 600, owned by lars. Missing-file is
|
|
24
35
|
# tolerated here (the script fails loudly if the vars are unset) so a
|
|
25
36
|
# fresh install doesn't fail to load the unit before creds are dropped in.
|
|
26
|
-
EnvironmentFile=-/etc/
|
|
37
|
+
EnvironmentFile=-/etc/__CONFIG_DIR__/spaces.env
|
|
27
38
|
# Hardening — the script reads dumps from /var/backups/gds and talks to the
|
|
28
39
|
# network. It needs no write access to the local filesystem.
|
|
29
40
|
NoNewPrivileges=true
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
# TEMPLATE — not installable as-is (task 1002757). The __TOKENS__ below MUST be
|
|
2
|
+
# substituted at install time; a provisioned instance gets a correct per-instance
|
|
3
|
+
# unit pair generated by scripts/gds/provision.js (task 2213) and never needs this
|
|
4
|
+
# file. Substitute:
|
|
5
|
+
# __SERVICE_USER__ the unix user that owns the instance + its Postgres role
|
|
6
|
+
# __INSTANCE_ROOT__ the instance checkout root (docs live under it)
|
|
7
|
+
# __CORE_SCRIPTS_DIR__ the deployed core's scripts/gds dir:
|
|
8
|
+
# standalone: <instance-root>/node_modules/@bongos/core/scripts/gds
|
|
9
|
+
# full clone: <instance-root>/scripts/gds
|
|
10
|
+
# __CONFIG_DIR__ the instance config dir name (offsite unit only)
|
|
11
|
+
# One-liner: sed -e 's|__SERVICE_USER__|<user>|g' -e … gds-db-backup.service | sudo tee /etc/systemd/system/…
|
|
1
12
|
[Unit]
|
|
2
13
|
Description=Weekly timer for GDS DB offsite archive to Spaces (filed by #415)
|
|
3
|
-
Documentation=file
|
|
14
|
+
Documentation=file://__INSTANCE_ROOT__/docs/recipes/gds-db-backup.md
|
|
4
15
|
|
|
5
16
|
[Timer]
|
|
6
17
|
# Run weekly on Sunday at 05:00 UTC. That's one hour after the daily local
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// instance-apex.js — the instance's own registrable apex + the addresses derived
|
|
3
|
+
// from it, read from its branding pack (task 1002757).
|
|
4
|
+
//
|
|
5
|
+
// WHY THIS EXISTS. Operator-plane defaults used to carry the founder's apex as a
|
|
6
|
+
// literal (box DNS zones, the Cloudflare zone, the provisioner's git identity),
|
|
7
|
+
// so another operator's fleet pointed at the founder's DNS and its commits were
|
|
8
|
+
// attributed to the hub. These resolvers return NULL rather than guessing when the
|
|
9
|
+
// pack names no public origin: every caller treats null as "not configured" and
|
|
10
|
+
// refuses, which fails loudly instead of minting an unreachable host.
|
|
11
|
+
function instanceApex() {
|
|
12
|
+
try {
|
|
13
|
+
const host = new URL(require('../../src/branding').branding().domains.publicOrigin).hostname;
|
|
14
|
+
return host && !/^localhost$/i.test(host) ? host : null;
|
|
15
|
+
} catch { return null; }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// The git identity a provisioner commits scaffold/pin changes as: explicit env →
|
|
19
|
+
// bot@<instance apex> → a neutral, deliberately-undeliverable platform address
|
|
20
|
+
// (never a live inbox by accident).
|
|
21
|
+
function provisionerBotEmail(env = process.env) {
|
|
22
|
+
const explicit = String(env.PROVISION_BOT_EMAIL || '').trim();
|
|
23
|
+
if (explicit) return explicit;
|
|
24
|
+
const apex = instanceApex();
|
|
25
|
+
return apex ? `bot@${apex}` : 'bot@cloud-bongos.invalid';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { instanceApex, provisionerBotEmail };
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"est_minutes": 55,
|
|
50
50
|
"credits_reward": 15,
|
|
51
51
|
"title": "Generate one new in-world art asset of your choice (a prop, plant, animal, or accessory) via the pixel-art pipeline",
|
|
52
|
-
"description": "## What you're doing\n\
|
|
52
|
+
"description": "## What you're doing\n\nThis instance's world always needs more to look at. Your first ship as an artist is to **generate ONE new in-world asset of your own choosing** and add it to the world. You pick the subject — that's the fun part. Good candidates, all in-world (Mediterranean coast just south of Athens, mythic 'discovered secret' tone):\n- **Props**: amphora, fishing net, basket, crate, urn, torch, market awning, oar, clay pot.\n- **Plants**: olive tree, cypress, reeds, grapevine, shrub, wild herbs.\n- **Animals**: goat, chicken, duck, donkey, fish, gull, lizard.\n- **Accessories**: a sandal, a sun hat, a length of rope, a string of beads.\n\nIt is identical for every newcomer and **always valuable**, because a growing world has effectively unbounded demand for new props, flora, fauna, and detail — every newcomer picks a different subject, so two runs never collide.\n\n## How to find your way in\n\n1. Read `art/README.md` and `docs/recipes/pixel-art-pipeline.md`, plus `modules/art-pipeline/template/style_guide.md`, `modules/art-pipeline/template/rubric.json`, and `modules/art-pipeline/template/palette.json` — that's the look you must hit: 16-bit pixel art, early-Pokémon (FireRed) touchstone, top-down, 32×32, locked 64-colour Mediterranean palette (olive greens, warm tans, turquoise sea, weathered marble — NOT spring green, NOT navy, NOT pine).\n2. **Pick ONE subject.** Keep it to a SINGLE 32×32 tile/sprite — not a whole spritesheet or family (that's a bigger task).\n3. **Check the budget first**: `python3 modules/art-pipeline/pipeline/cost_ledger.py status` (the pipeline hard-stops at $80; one asset is ~$0.05–0.45).\n4. **Generate via the pipeline — do not hand-draw or freelance.** Use the `/otb-tile-generate` skill: it appends your new entry to `modules/art-pipeline/template/vocabulary.json`, runs the generate → post-process-to-32×32 → score-against-rubric → retry orchestrator, saves the final PNG to `modules/art-pipeline/generated/tiles/<id>.png`, and logs cost. (This needs the art pipeline's `GOOGLE_AI_STUDIO_KEY`, which resolves from `~/.config/otb/env`; most builder setups have it. If yours doesn't, claim the engineer or ideator newcomer chore instead, or ask an Archon to enable it.)\n5. **Confirm it PASSED** the rubric (`modules/art-pipeline/iterations/run_summary.json` shows `status: \"pass\"`). If it only reached best-effort, regenerate with the fix_hint — never paper over a fail.\n6. **See it in-game**: `node scripts/gds/art-stage.js` rebuilds the atlas and surfaces it on your sandbox preview (`sandbox-<login>.<instance-apex>`).\n7. Ship via `/builder-ship`; the ship notes name your asset and its rubric score.\n\n## Stay clear of (READ-ONLY)\n\nNever modify the locked palette (`modules/art-pipeline/template/palette.json`) or the rubric (`modules/art-pipeline/template/rubric.json`) — those are theme-defining and changing them needs an ADR (out of scope for a first ship). Touch only art assets/vocabulary under `art/` (and, only if your asset is a genuinely new base-tile TYPE, the `public/game/world/tilePalette.js` mapping). Do not touch any permission/pipeline-core/migration/infra file.",
|
|
53
53
|
"done_when": [
|
|
54
54
|
"Exactly one NEW in-world asset (your chosen subject) was generated via the pixel-art pipeline (`/otb-tile-generate` / orchestrator.py); the final PNG exists at modules/art-pipeline/generated/tiles/<id>.png.",
|
|
55
55
|
"It PASSED the rubric (modules/art-pipeline/iterations/run_summary.json status 'pass', or /otb-design-review numbers reported at/above the bar) and every pixel is on the locked palette (modules/art-pipeline/template/palette.json).",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"est_minutes": 45,
|
|
71
71
|
"credits_reward": 12,
|
|
72
72
|
"title": "Idea-seed pass: file 5-8 fresh in-world ideas (names, lore, or builder-UX) into the idea inbox",
|
|
73
|
-
"description": "## What you'll do\n\nThe seed of almost everything built here is the **idea_inbox** — a queue anyone can drop ideas into, which trusted builders later triage into real tasks. Your first ship as an ideator is simple and concrete: **add a small batch of fresh ideas to that inbox.** You write no code, touch no game, change no system — you think, write a few short well-shaped ideas, and file them with one command each.\n\nIt is identical for every newcomer and **always valuable**: the inbox is never \"done\" — every triage pass consumes ideas (promote/discard/merge), so it is permanently hungry for fresh input, and a world
|
|
73
|
+
"description": "## What you'll do\n\nThe seed of almost everything built here is the **idea_inbox** — a queue anyone can drop ideas into, which trusted builders later triage into real tasks. Your first ship as an ideator is simple and concrete: **add a small batch of fresh ideas to that inbox.** You write no code, touch no game, change no system — you think, write a few short well-shaped ideas, and file them with one command each.\n\nIt is identical for every newcomer and **always valuable**: the inbox is never \"done\" — every triage pass consumes ideas (promote/discard/merge), so it is permanently hungry for fresh input, and a growing world always wants more names, more lore, more texture. Your batch is brand-new content, so it can never duplicate \"the work\" — the supply IS the work.\n\n## Pick ONE branch\n\n- **Branch A — PRODUCT flavour (default).** Ideas that grow the world players see: **names + one line of lore** for a character, structure, landmark, district, ship, or festival; or a world-background snippet (a custom, a superstition, a line a named NPC says). Tone: mythic, mysterious, a \"discovered secret\"; Mediterranean ancient-Greek coast (just south of Athens); NOT modern, NOT tongue-in-cheek-modern. Ground it in CLAUDE.md §3/§6/§7.\n- **Branch B — INTERNAL / builder-UX.** Small user-experience improvement ideas for the GDS / builders' hall (the surfaces builders use, not the game): a clearer label, a confusing onboarding message, a quality-of-life tweak to a status page or a slash-command's output. See `docs/TRACKS.md` for product vs internal.\n\n## How to find your way in\n\n1. (Branch A) Read CLAUDE.md §3/§6/§7 for tone. (Branch B) Skim `docs/TRACKS.md` and click around your instance's /builders hall for the rough edge you'll write up.\n2. See what's already filed so you don't repeat it: `node scripts/gds/api.js GET /api/gds/inbox`.\n3. File each idea with `node scripts/gds/capture.js \"<title>\" --body-file <path>` (filing an idea is the open-to-all path — a Xenos/Thetes session is allowed to do it; you just can't triage them). Put one line of detail + a `track: product` or `track: internal` line in each body file.",
|
|
74
74
|
"done_when": [
|
|
75
75
|
"You filed 5–8 fresh ideas into the idea_inbox via `node scripts/gds/capture.js` (each prints a `Captured idea #N` confirmation), all in ONE branch (A product, or B internal/UX).",
|
|
76
76
|
"Each idea has a clear title and a body with at least one sentence of detail — for Branch A, one line of in-world lore (who/what it is); for Branch B, what the rough edge is and what 'better' looks like.",
|
package/scripts/gds/provision.js
CHANGED
|
@@ -169,6 +169,10 @@ const CONFIG = {
|
|
|
169
169
|
sshOpts: process.env.PROVISION_SSH_OPTS || '-o BatchMode=yes -o StrictHostKeyChecking=accept-new',
|
|
170
170
|
};
|
|
171
171
|
|
|
172
|
+
// task 1002757 — the provisioner's git identity resolves from the instance's own
|
|
173
|
+
// apex (env → bot@<apex> → neutral), never the hub's address hardcoded.
|
|
174
|
+
const { provisionerBotEmail } = require('./instance-apex');
|
|
175
|
+
|
|
172
176
|
const MAX_INTENT_ATTEMPTS = numEnv('PROVISION_INTENT_MAX_ATTEMPTS', 3);
|
|
173
177
|
|
|
174
178
|
// Manifest-placement verification budget (task 1002720 / QA-walk F23): a child
|
|
@@ -709,7 +713,7 @@ async function scaffoldStandaloneRepo(inst, deps) {
|
|
|
709
713
|
writeFile(giPath, INSTANCE_GITIGNORE);
|
|
710
714
|
}
|
|
711
715
|
exec(`git -C ${root} config user.name "Cloud Bongos"`);
|
|
712
|
-
exec(`git -C ${root} config user.email "
|
|
716
|
+
exec(`git -C ${root} config user.email "${provisionerBotEmail()}"`);
|
|
713
717
|
exec(`git -C ${root} add -A`);
|
|
714
718
|
const commitMsg = mode === 'adopt'
|
|
715
719
|
? `chore: adopt Cloud Bongos onto ${inst.slug} on a pinned @bongos/core ${coreV} (provision.js, ADR 0121)`
|
|
@@ -939,7 +943,7 @@ function buildCorePinRefreshCommit({ root, fromVersion, toVersion, repo, ownerTo
|
|
|
939
943
|
return {
|
|
940
944
|
config: [
|
|
941
945
|
`git -C ${root} config user.name "Cloud Bongos"`,
|
|
942
|
-
`git -C ${root} config user.email "
|
|
946
|
+
`git -C ${root} config user.email "${provisionerBotEmail()}"`,
|
|
943
947
|
],
|
|
944
948
|
add: `git -C ${root} add -A`,
|
|
945
949
|
commit: `git -C ${root} commit -m "${msg}"`,
|
|
@@ -2477,7 +2481,7 @@ async function main() {
|
|
|
2477
2481
|
if (require.main === module) main();
|
|
2478
2482
|
|
|
2479
2483
|
module.exports = {
|
|
2480
|
-
CONFIG, MAX_INTENT_ATTEMPTS,
|
|
2484
|
+
CONFIG, MAX_INTENT_ATTEMPTS, provisionerBotEmail,
|
|
2481
2485
|
// pure step generators (tested directly)
|
|
2482
2486
|
dbName, dbCreateCmd, migrateCmd, seedFirstVersionCmd, serviceUnit, serviceUnitPath, webEnvBody, webEnvPath,
|
|
2483
2487
|
backupUnitName, backupServicePath, backupTimerPath, backupScriptPath, backupService, backupTimer,
|