@bongos/core 1.19.1049 → 1.19.1051
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 +22 -52
- package/docs/file-map.md +1 -9
- package/docs/module-api-changelog.md +4 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/gds/publish-manifest.js +0 -1
- package/scripts/gds/seed-bv2-tweak-mode-tasks.js +277 -0
- package/scripts/setup-builder.sh +3 -3
- package/src/bongos/module-scope-map.js +2 -15
- package/src/module-api.js +1 -1
- package/.devcontainer/Dockerfile +0 -69
- package/.devcontainer/README.md +0 -73
- package/.devcontainer/devcontainer-lock.json +0 -19
- package/.devcontainer/devcontainer.json +0 -93
- package/.devcontainer/healthcheck.sh +0 -84
- package/.devcontainer/init-firewall.sh +0 -234
- package/.devcontainer/post-create.sh +0 -149
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.1051",
|
|
6
|
+
"core_contract": "1.19.1051",
|
|
7
|
+
"source_commit": "f906f1ac8fe670e81ef2187fa4e8f592148b1d66",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-28T02:19:36.415Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 542,
|
|
13
13
|
"agent_docs_stubbed": 26,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2508,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 3077,
|
|
20
|
+
"tree_sha256": "a4eccd902a2864a71fa57eb469423bdd6cce0464835ed1e695fd011e0e4d8e8e",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -259,41 +259,6 @@
|
|
|
259
259
|
"mode": "0000644",
|
|
260
260
|
"sha256": "6548fe1de89c6909def02b76f022cae739c5b129d179a63538b9a1ab252e5030"
|
|
261
261
|
},
|
|
262
|
-
{
|
|
263
|
-
"path": ".devcontainer/Dockerfile",
|
|
264
|
-
"mode": "0000644",
|
|
265
|
-
"sha256": "8e2a619a3d72bfcb91440fd5773622fefb773b5effea1e6c7f7d6c2e01f14817"
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
"path": ".devcontainer/README.md",
|
|
269
|
-
"mode": "0000644",
|
|
270
|
-
"sha256": "33038ae214c708ce3e5c2539c5e672e82da76b882df93d6d906a041fc22253bb"
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
"path": ".devcontainer/devcontainer-lock.json",
|
|
274
|
-
"mode": "0000644",
|
|
275
|
-
"sha256": "ef6b1d2b6d7fdaea6d1a6b0d91378fa18e2f9f49bdf8ffbf541f8659d68574dc"
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
"path": ".devcontainer/devcontainer.json",
|
|
279
|
-
"mode": "0000644",
|
|
280
|
-
"sha256": "4ea21a7f615b5f9cb3a657f6c053d3680aed99c9c33cc70cbac398068fd6c309"
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
"path": ".devcontainer/healthcheck.sh",
|
|
284
|
-
"mode": "0000644",
|
|
285
|
-
"sha256": "5b04ae8e3436e659339eb0f820623844d22ccdbd07d6e9775aa6df17f6d1dd30"
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
"path": ".devcontainer/init-firewall.sh",
|
|
289
|
-
"mode": "0000644",
|
|
290
|
-
"sha256": "bcff88c5ca2835456f43992b6d9506e62ffb1475e20d7b15819f4572f5abb5ee"
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
"path": ".devcontainer/post-create.sh",
|
|
294
|
-
"mode": "0000644",
|
|
295
|
-
"sha256": "ba1f564c1d91473e545a1e33051a4c1952db037e5e607b1d219bde97280174b7"
|
|
296
|
-
},
|
|
297
262
|
{
|
|
298
263
|
"path": ".dockerignore",
|
|
299
264
|
"mode": "0000644",
|
|
@@ -2762,7 +2727,7 @@
|
|
|
2762
2727
|
{
|
|
2763
2728
|
"path": "docs/file-map.md",
|
|
2764
2729
|
"mode": "0000644",
|
|
2765
|
-
"sha256": "
|
|
2730
|
+
"sha256": "64d65a849596466c7fbafba381668129c2e305e88af805dc5eed06a5b06600bb"
|
|
2766
2731
|
},
|
|
2767
2732
|
{
|
|
2768
2733
|
"path": "docs/handoff-template.md",
|
|
@@ -2772,7 +2737,7 @@
|
|
|
2772
2737
|
{
|
|
2773
2738
|
"path": "docs/module-api-changelog.md",
|
|
2774
2739
|
"mode": "0000644",
|
|
2775
|
-
"sha256": "
|
|
2740
|
+
"sha256": "693a1c4a611f8d87c269256437b7bb863f43f176e9bbf95dbfdf5ab6f869171f"
|
|
2776
2741
|
},
|
|
2777
2742
|
{
|
|
2778
2743
|
"path": "docs/modules-contract.md",
|
|
@@ -8497,12 +8462,12 @@
|
|
|
8497
8462
|
{
|
|
8498
8463
|
"path": "package-lock.json",
|
|
8499
8464
|
"mode": "0000644",
|
|
8500
|
-
"sha256": "
|
|
8465
|
+
"sha256": "dfa68dc6e56624b0b3f146d4a26e3711cd467b931b61f986675af5696b446c9d"
|
|
8501
8466
|
},
|
|
8502
8467
|
{
|
|
8503
8468
|
"path": "package.json",
|
|
8504
8469
|
"mode": "0000644",
|
|
8505
|
-
"sha256": "
|
|
8470
|
+
"sha256": "82a4ab7a958fdea55a57c37d85fc5c60fb8e6cfb0206a53ecf19ea779f2b1418"
|
|
8506
8471
|
},
|
|
8507
8472
|
{
|
|
8508
8473
|
"path": "public-docs/index.html",
|
|
@@ -8522,7 +8487,7 @@
|
|
|
8522
8487
|
{
|
|
8523
8488
|
"path": "release-notes.json",
|
|
8524
8489
|
"mode": "0000644",
|
|
8525
|
-
"sha256": "
|
|
8490
|
+
"sha256": "f6aa782dbdddd40935bd0a1742212cd0c4b839b3b29210bc0ecc8cb4106ec747"
|
|
8526
8491
|
},
|
|
8527
8492
|
{
|
|
8528
8493
|
"path": "scripts/bongos-mcp.js",
|
|
@@ -9532,7 +9497,7 @@
|
|
|
9532
9497
|
{
|
|
9533
9498
|
"path": "scripts/gds/publish-manifest.js",
|
|
9534
9499
|
"mode": "0000644",
|
|
9535
|
-
"sha256": "
|
|
9500
|
+
"sha256": "17cb93e59d7f05319d8245fcbe9e55d5821c559680ce65f28fef763afece3b4c"
|
|
9536
9501
|
},
|
|
9537
9502
|
{
|
|
9538
9503
|
"path": "scripts/gds/publish-watch.js",
|
|
@@ -9779,6 +9744,11 @@
|
|
|
9779
9744
|
"mode": "0000644",
|
|
9780
9745
|
"sha256": "1e74a2b1582922bbab8be30e62f8276f9d22e69d42210783940abcfcb618c603"
|
|
9781
9746
|
},
|
|
9747
|
+
{
|
|
9748
|
+
"path": "scripts/gds/seed-bv2-tweak-mode-tasks.js",
|
|
9749
|
+
"mode": "0000644",
|
|
9750
|
+
"sha256": "268bc8270f4b6c81fa9e3fe9d76e33aab9aa93a645136e9c105bbbd9775e6f0a"
|
|
9751
|
+
},
|
|
9782
9752
|
{
|
|
9783
9753
|
"path": "scripts/gds/seed-gds-v4-tasks.js",
|
|
9784
9754
|
"mode": "0000644",
|
|
@@ -10217,7 +10187,7 @@
|
|
|
10217
10187
|
{
|
|
10218
10188
|
"path": "scripts/setup-builder.sh",
|
|
10219
10189
|
"mode": "0000644",
|
|
10220
|
-
"sha256": "
|
|
10190
|
+
"sha256": "f449553cc1965f6801e7a72a1dc90724ad7556eb047834c73c77ae9ab7ae2f76"
|
|
10221
10191
|
},
|
|
10222
10192
|
{
|
|
10223
10193
|
"path": "scripts/status-mirror-sync.js",
|
|
@@ -10387,7 +10357,7 @@
|
|
|
10387
10357
|
{
|
|
10388
10358
|
"path": "src/bongos/module-scope-map.js",
|
|
10389
10359
|
"mode": "0000644",
|
|
10390
|
-
"sha256": "
|
|
10360
|
+
"sha256": "8f15e21380fe09d31b1a19d98415e502c81e41e566eda2fc9ec2496d8044eae9"
|
|
10391
10361
|
},
|
|
10392
10362
|
{
|
|
10393
10363
|
"path": "src/bongos/module-submissions.js",
|
|
@@ -10592,7 +10562,7 @@
|
|
|
10592
10562
|
{
|
|
10593
10563
|
"path": "src/module-api.js",
|
|
10594
10564
|
"mode": "0000644",
|
|
10595
|
-
"sha256": "
|
|
10565
|
+
"sha256": "43fd679c4d3db919ecd3a83c0768de05e6be3d4d243749f1873fff3faa44744a"
|
|
10596
10566
|
},
|
|
10597
10567
|
{
|
|
10598
10568
|
"path": "src/module-loader/catalog.js",
|
package/docs/file-map.md
CHANGED
|
@@ -17,14 +17,6 @@
|
|
|
17
17
|
├── CODEOWNERS ← owner review on the merge-gate surfaces (real since task 1002611, ADR 0159); inert until branch protection is on (scripts/gds/gating.js) — keep aligned with gate-review.js HARD_FLOOR_GLOBS
|
|
18
18
|
├── server.js ← game boot: Express + Colyseus + the shared internal surface (mountInternalSurfaces), binds 127.0.0.1:3000
|
|
19
19
|
│
|
|
20
|
-
├── .devcontainer/ ← the Example Dev Box, defined as code (ADR 0031 §3) — builds identically on a DO box + a laptop
|
|
21
|
-
│ ├── devcontainer.json ← box spec: features (Node 22, gh, Claude Code), NET_ADMIN caps, persisted volumes, lifecycle hooks
|
|
22
|
-
│ ├── Dockerfile ← Ubuntu 24.04 base + Python 3.12 venv + firewall/art system deps + build-time integrity assert
|
|
23
|
-
│ ├── init-firewall.sh ← postStart default-deny outbound firewall, tight allow-list (ADR 0031 §6)
|
|
24
|
-
│ ├── post-create.sh ← first-run: folds in setup-builder.sh --no-auth + art deps + full-stack verify
|
|
25
|
-
│ ├── healthcheck.sh ← image-level toolchain integrity check (the image half of doctor-as-health-check)
|
|
26
|
-
│ └── README.md ← box docs, ADR mapping, deliberate reconciliations, out-of-scope tasks
|
|
27
|
-
│
|
|
28
20
|
├── limitations/ ← versioning-methodology artifacts
|
|
29
21
|
│ ├── README.md
|
|
30
22
|
│ ├── v1-shipped.md ← V1 game archive (shipped 2026-05-12)
|
|
@@ -150,7 +142,7 @@
|
|
|
150
142
|
│ ├── migrate.sh ← idempotent migration runner; applies core `migrations/*.sql` always + `modules/<key>/migrations/*.sql` only when the module is enabled (ADR 0083 §module-owned-migrations); stem-keyed so relocating a migration between dirs never re-runs it on prod
|
|
151
143
|
│ ├── verify-gds-only-schema.sh ← task 1191: throwaway-DB proof that a Bongos-only migration run yields the build-system schema with NO game tables (needs local Postgres; not the DB-free unit gate)
|
|
152
144
|
│ ├── setup-builder.js ← one-command new-builder bootstrap (toolchain + npm ci + .env.local + Bongos auth); cross-platform node entry (#673)
|
|
153
|
-
│ ├── setup-builder.sh ← thin bash shim → setup-builder.js (Mac/Linux convenience +
|
|
145
|
+
│ ├── setup-builder.sh ← thin bash shim → setup-builder.js (Mac/Linux convenience + README refs)
|
|
154
146
|
│ ├── deploy/ ← deploy scripts that run ON the droplet
|
|
155
147
|
│ │ ├── deploy-prod.sh ← #1026/ADR 0056: version-controlled MIRROR of the droplet's hand-maintained ~/deploy.sh (byte-faithful). NOT auto-installed — the ci deploy key is forced-command-locked (ADR 0042/0043); reinstall by hand on change. Localhost /healthz retried 15×@1s so a slow bind no longer false-fails a deploy.
|
|
156
148
|
│ │ ├── deploy-staging.sh ← #261: staging analogue of ~/deploy.sh; scp'd to ~/deploy-staging.sh + run by deploy-staging.yml on push to `staging` (same healthz retry)
|
|
@@ -2585,5 +2585,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2585
2585
|
landed since 1.19.1047 with no explicit bump. run 36285856717. (task 1002620)
|
|
2586
2586
|
1.19.1049 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2587
2587
|
landed since 1.19.1048 with no explicit bump. run 36323359891. (task 1002620)
|
|
2588
|
+
1.19.1050 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2589
|
+
landed since 1.19.1049 with no explicit bump. run 36324195800. (task 1002620)
|
|
2590
|
+
1.19.1051 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2591
|
+
landed since 1.19.1050 with no explicit bump. run 36369343116. (task 1002620)
|
|
2588
2592
|
---------------------------------------------------------------------------
|
|
2589
2593
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1051",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.1051",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1051",
|
|
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
|
@@ -7595,5 +7595,17 @@
|
|
|
7595
7595
|
"id": "1003969",
|
|
7596
7596
|
"text": "cloudbongos.com now checks for a new version every 15 minutes instead of once a day, so merged work goes live within about a quarter of an hour."
|
|
7597
7597
|
}
|
|
7598
|
+
],
|
|
7599
|
+
"1.19.1050": [
|
|
7600
|
+
{
|
|
7601
|
+
"id": "1003896",
|
|
7602
|
+
"text": "Removed the leftover dev-box container setup and the automated check that built it, so nothing in the project still describes or builds the retired dev box environment."
|
|
7603
|
+
}
|
|
7604
|
+
],
|
|
7605
|
+
"1.19.1051": [
|
|
7606
|
+
{
|
|
7607
|
+
"id": "1004312",
|
|
7608
|
+
"text": "Tweak Mode is planned and queued. An artist will take a whole page of the site from one calm studio, rewrite every word of it as a document (or offline in Word, uploaded back), and approve the finished page before it goes live"
|
|
7609
|
+
}
|
|
7598
7610
|
]
|
|
7599
7611
|
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// scripts/gds/seed-bv2-tweak-mode-tasks.js — seed the Tweak Mode chain into goal 1000095 (planning session, task 1004312)
|
|
2
|
+
//
|
|
3
|
+
// WHY. The 2026-09-27 planning session settled Tweak Mode — an artist takes a
|
|
4
|
+
// whole page from the lofi studio, rewrites every word of it as one document
|
|
5
|
+
// (or offline in Word and uploads it back), submits, and approves the applied
|
|
6
|
+
// page before it ships — as a dependency CHAIN inside the existing
|
|
7
|
+
// working-area-6 goal. Tweak Mode REPLACES the per-ship artist review (same
|
|
8
|
+
// payouts), text only for now. Source of truth: docs/specs/bongos-v2-tweak-mode.md
|
|
9
|
+
// (final); the approved screens: docs/design/mocks/tweak-mode/.
|
|
10
|
+
//
|
|
11
|
+
// Lands: one criterion, the scope widening the chain needs, the new tasks, the
|
|
12
|
+
// rescope of 1003971 (1004238 merged into it), 1004078 merged into TW14, a
|
|
13
|
+
// split-off backlog task for ARTIST MODE's photo half, and every edge.
|
|
14
|
+
//
|
|
15
|
+
// Idempotent: tasks on (source, source_ref) — a reused ref returns 200 with the
|
|
16
|
+
// FIRST row, so a 200 whose title is not ours is reported, not trusted; the
|
|
17
|
+
// criterion on criterion_id (409 = already seeded); scope is a set-union; edges
|
|
18
|
+
// and criterion links are idempotent server-side; merge reports already_merged.
|
|
19
|
+
//
|
|
20
|
+
// Ends with verifySeedCriteriaLinks. The goal already carries other criteria, so
|
|
21
|
+
// the expected counts are the goal's PRE-seed linked_tasks plus this seed's plan
|
|
22
|
+
// (re-running after a full success therefore reports a mismatch on wa6-tweak-mode:
|
|
23
|
+
// that is the plan being counted twice, not a mislink).
|
|
24
|
+
//
|
|
25
|
+
// Run: node scripts/gds/seed-bv2-tweak-mode-tasks.js [--dry-run]
|
|
26
|
+
const os = require('os');
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
const { verifySeedCriteriaLinks } = require('./seed-verify-criteria');
|
|
30
|
+
// cliExit, never process.exit after a request: a hard exit mid-teardown aborts
|
|
31
|
+
// natively on Windows + Node 24 and reports a false exit code (task 1002734).
|
|
32
|
+
const { cliExit } = require('./cli-lib');
|
|
33
|
+
|
|
34
|
+
function loadSession() {
|
|
35
|
+
const candidates = [
|
|
36
|
+
path.join(os.homedir(), '.config', 'cloudbongos', 'gds-session.json'),
|
|
37
|
+
path.join(os.homedir(), '.config', 'otb', 'gds-session.json'),
|
|
38
|
+
];
|
|
39
|
+
for (const p of candidates) if (fs.existsSync(p)) return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
40
|
+
throw new Error('no Bongos session found — run /builder-setup');
|
|
41
|
+
}
|
|
42
|
+
const sess = loadSession();
|
|
43
|
+
const BASE = (process.env.GDS_API_BASE || sess.api_base).replace(/\/$/, '');
|
|
44
|
+
const H = { Authorization: `Bearer ${sess.token}`, 'Content-Type': 'application/json' };
|
|
45
|
+
const DRY = process.argv.includes('--dry-run');
|
|
46
|
+
|
|
47
|
+
const VER = 'BONGOS-V2';
|
|
48
|
+
const GOAL = 1000095;
|
|
49
|
+
const SRC = 'planning-session';
|
|
50
|
+
const REF = 'bv2-tweak-mode';
|
|
51
|
+
const CRIT = 'wa6-tweak-mode';
|
|
52
|
+
const SPEC = 'docs/specs/bongos-v2-tweak-mode.md';
|
|
53
|
+
const MOCKS = 'docs/design/mocks/tweak-mode/';
|
|
54
|
+
const ARTIST_MODE = 1003971; // rescoped into TW16
|
|
55
|
+
const LOFI_PAGE = 1004238; // merged into 1003971
|
|
56
|
+
const STUDIO_COPY = 1004078; // merged into TW14
|
|
57
|
+
const SCOPE_ADD = ['copy-desk', 'ui-design', 'public-landing', 'status-ui', 'economy'];
|
|
58
|
+
|
|
59
|
+
const CRITERION_MD = `**An artist can take any page of their project from untweaked to tweaked without leaving the studio or touching a terminal.**
|
|
60
|
+
|
|
61
|
+
Today an artist's work arrives as one review task per ship and one flag per string, which cannot keep up with how much the project ships; most of it was abandoned unread. When this is true, the page is the unit of an artist's work, and it all happens from one calm place:
|
|
62
|
+
|
|
63
|
+
- The studio is a lofi home with four doors: Resume, Tweak/CopyWrite Flow, Approval queue and Artist Review Status. The last three open in place as glass panels, and the studio's own words can be rewritten where they stand. The artist's credit tally sits in the corner.
|
|
64
|
+
- Every page on every surface (landing, builders hall, status) has a tweak status with a count ("text tweaked 2x"), a changelog and a changed-since-last-tweak marker. Artist Review Status sums it per surface in three lines.
|
|
65
|
+
- The Tweak/CopyWrite Flow recommends the next page (asked-for first, then changed, then untweaked) and lets the artist pick another; taking it claims the page for them alone.
|
|
66
|
+
- The artist sees every word the rendered page shows as one document and types over it, or downloads it as a .docx, works offline, and uploads it back into the draft. The draft survives closing the tab. One submit, then "next up".
|
|
67
|
+
- The applied page is rendered in the Approval queue, flipped between before and after with the changed words highlighted; nothing ships until the artist approves or sends it back with a note.
|
|
68
|
+
- Text only: nothing structural can change, and shared text changes only on the page being tweaked unless it is literally the same UI element. Text the tool cannot place in the source goes to an engineer as its own task.
|
|
69
|
+
- Tweak Mode replaces the per-ship artist review, and the artist is paid for an approved page what the reviews paid.
|
|
70
|
+
- It works on any Bongos project.
|
|
71
|
+
|
|
72
|
+
*Written 2026-09-27 by the area owner (planning session, task 1004312). Spec: ${SPEC}. Screens: ${MOCKS}.*`;
|
|
73
|
+
|
|
74
|
+
const S = `Spec: ${SPEC} (Tweak Mode chain, goal 1000095). Prototype: ${MOCKS} (README maps each screen).`;
|
|
75
|
+
// The prototype is the MASTER: screens are built 1:1 on it, and the proof is a
|
|
76
|
+
// side-by-side, not a claim.
|
|
77
|
+
const PIXEL = (board, part) => `\n\nPIXEL CONTRACT (1:1): ${MOCKS}${board}${part ? ` (${part})` : ''} is the master design, approved by the owner. Build it 1:1: the same layout, words, sizes, colours, glass and states. Before shipping, render the built page with modules/ui-design/kit at 1440 and 390 wide, in light and dark, and put each render beside the artboard with scripts/gds/review-sheet.js. Every difference is either fixed or listed in the ship notes with the gate or route that forced it. An unlisted difference is a defect.`;
|
|
78
|
+
|
|
79
|
+
const TASKS = [
|
|
80
|
+
{ ref: 'TW01', kind: 'infra', disc: 'engineer', prio: 5, est: 30, deps: [],
|
|
81
|
+
title: 'BV2.TW01 · Turn the artist gate off on the Cloud Bongos instance',
|
|
82
|
+
desc: `Owner decision 2026-09-27: the artist gate (ADR 0241) is off for now; approval of page tweaks moves into the studio's Approval queue (TW12).\n\nSet the Cloud Bongos instance's artistGate to 'off' through the provisioning settings path (modules/provisioning, the artistGate vocabulary key), not by hand-editing a host file. Record the before/after value on this task. Task 1004107 (the gate's contradiction) stays open for when the gate returns.\n\nDONE WHEN: the live instance reports artistGate 'off' and a deploy is no longer held by an unresolved artist review. ${S}` },
|
|
83
|
+
{ ref: 'TW02', kind: 'feature', disc: 'engineer', prio: 5, est: 150, deps: [],
|
|
84
|
+
title: 'BV2.TW02 · Page inventory: every page of every surface gets a stable id',
|
|
85
|
+
desc: `The PAGE is Tweak Mode's unit, and pages are implicit today (body[data-page] in the hall, file names on landing and status). Generate an inventory: for each surface (builders hall, landing, status) every page with a stable id, title, live url, the files that render it, and its .states.json states where present. Portable: derived from the modules an instance has enabled. Freshness-checked like the copy registry (a --check the ship pipeline runs).\n\nDONE WHEN: the inventory lists every hall, landing and status page with stable ids and a --check fails on drift. ${S}` },
|
|
86
|
+
{ ref: 'TW03', kind: 'feature', disc: 'engineer', prio: 5, est: 120, deps: ['TW02'],
|
|
87
|
+
title: 'BV2.TW03 · ADR: write down the page tweak model',
|
|
88
|
+
desc: `The owner has already made these decisions (spec, "Design decisions"); this task WRITES THEM DOWN as one ADR so every later task builds on the same model. It is not a design pass: where the spec is genuinely silent, file a blocker for the owner rather than choosing. The ADR records:\n- page status DERIVED from the ledger (approved, shipped tweak tasks per page id; text and ui counts), the changelog, drift ("changed since last tweak"), and the per-surface Artist Review Status sums;\n- one active tweak per page, the claim, page asks, and the recommendation order (asked-for, then changed, then untweaked);\n- the draft kept on the tweak task and the page-batch proposal (amends ADR 0233), with copy_no_cms.mjs staying green;\n- the .docx round trip: the file's shape, how an upload maps back to lines, and what an upload that changes structure is refused with;\n- the waiting-for-artist state and send-back;\n- REPLACING the artist-review-on-ship cascade (lifecycle/cascade.js), and paying an approved page what the reviews paid.\nConfirm or re-cut TW04–TW16 against it.\n\nDONE WHEN: the ADR is merged and TW04–TW16 match it. ${S}` },
|
|
89
|
+
{ ref: 'TW04', kind: 'feature', disc: 'engineer', prio: 5, est: 240, deps: ['TW02'],
|
|
90
|
+
title: 'BV2.TW04 · Page reader: every string a rendered page shows',
|
|
91
|
+
desc: `The copy registry (docs/copy-registry.json) is keyed by FILE, includes comment text no one sees, and misses runtime-built and server-sent text. The page reader answers "what does this page actually show": render each inventory page in each state (scripts/hall-preview/server.js fixtures + modules/ui-design/kit; landing and status the same way) and list every visible string in page order, grouped by section. Map each to a registry entry (file + line), or mark it UNPLACED; mark shared-shell text (top bar, footer) as a SHARED ELEMENT.\n\nDONE WHEN: every inventory page has a reading with placed / unplaced / shared marked, and a test proves an unplaced string is listed, not dropped. ${S}` },
|
|
92
|
+
{ ref: 'TW05', kind: 'feature', disc: 'engineer', prio: 5, est: 180, deps: ['TW03', 'TW04'],
|
|
93
|
+
title: 'BV2.TW05 · Page tweak status, Artist Review Status and the artist tally (the reads)',
|
|
94
|
+
desc: `Per TW03, derived from the ledger, no status table:\n- per page: status (Untweaked / Text tweaked / UI tweaked / Both), counts ("2x"), changelog (artist, date, lines, before/after), and changed-since-last-tweak lines;\n- per surface (Artist Review Status): "N of M tweaked";\n- per artist (the studio's corner tally): credits earned from page tweaks, pages tweaked, and this week's gain.\n\nDONE WHEN: all three reads are correct for a fixture with an untweaked page, a page tweaked twice, and a tweaked page whose text changed afterwards. ${S}` },
|
|
95
|
+
{ ref: 'TW06', kind: 'feature', disc: 'engineer', prio: 5, est: 120, deps: ['TW03'],
|
|
96
|
+
title: 'BV2.TW06 · Claim a page, and ask for one',
|
|
97
|
+
desc: `A builder holding the Artist role claims a page's tweak in one call, which creates (or reuses) the page's tweak task and claims it for them; a second claim while one is held is refused and names the holder. Anyone can ask for a page with a one-line reason; asks feed the recommendation (TW07). The page ask replaces per-string flags as the main signal.\n\nDONE WHEN: an artist claims a page; a second artist is refused with the holder named; a non-artist can ask but not claim. ${S}` },
|
|
98
|
+
{ ref: 'TW07', kind: 'feature', disc: 'engineer', prio: 5, est: 90, deps: ['TW05', 'TW06'],
|
|
99
|
+
title: 'BV2.TW07 · The Tweak/CopyWrite Flow: recommend the next page',
|
|
100
|
+
desc: `The chain the owner asked for: finish a page, get the next one. One read returns the recommended next page for this artist and why ("2 people asked for it"), plus a short list of alternatives for "pick another". Order per TW03: asked-for first, then changed since last tweak, then untweaked; never a page someone else holds. Taking it is TW06's claim.\n\nDONE WHEN: the recommendation follows the order on a fixture, skips held pages, and "take next" claims the recommended page in one call. ${S}` },
|
|
101
|
+
{ ref: 'TW08', kind: 'feature', disc: 'engineer', prio: 5, est: 180, deps: ['TW03', 'TW04', 'TW06'],
|
|
102
|
+
title: 'BV2.TW08 · Page-batch proposal with a saved draft',
|
|
103
|
+
desc: `Extend the copy-desk proposal (ADR 0233, amended by TW03) from one occurrence to a whole page. The artist's draft saves onto the page's tweak task as they write; submit freezes it into the page-batch patch and queues it for /tweak. A rewrite of an UNPLACED line files its own engineer task carrying the wording and does not block the page. Targets resolve server-side from the page reading, never from the request body.\n\nDONE WHEN: draft save, submit and the unplaced split work end to end, and modules/copy-desk/tests/copy_no_cms.mjs stays green. ${S}` },
|
|
104
|
+
{ ref: 'TW09', kind: 'feature', disc: 'engineer', prio: 5, est: 180, deps: ['TW08'],
|
|
105
|
+
title: 'BV2.TW09 · Work offline: download a page as .docx and upload it back',
|
|
106
|
+
desc: `Owner decision: an artist can download the page's words as a Word document, work offline, and upload it back into the draft. Download renders the page reading as a .docx (sections as headings, one paragraph per line, shared and engineer lines marked). Upload maps paragraphs back to lines per TW03 and merges them into the draft (never straight to the site). An upload that adds, drops or reorders lines is refused with a plain explanation of which lines moved. Cheapest viable library, no paid service.\n\nDONE WHEN: a round trip with edits lands those edits in the draft, and a structure-changing upload is refused by name. ${S}` },
|
|
107
|
+
{ ref: 'TW10', kind: 'feature', disc: 'ui', prio: 5, est: 240, deps: ['TW04', 'TW06', 'TW08', 'TW09'],
|
|
108
|
+
title: 'BV2.TW10 · The tweak editor: the whole page as one document',
|
|
109
|
+
desc: `The artist's own flow, not Claude's. Over the dimmed studio: a glass top bar (back to studio, page name, lines rewritten + saved, open the page in a new tab, download .docx, upload .docx, submit page) and one paper document holding every word of the page in page order, typed over in place, autosaving (TW08). A changed line carries a small accent mark and a faint "was:"; shared and engineer lines carry a margin note. Submit opens "<page> is in" with the next recommended page (TW07): take next, pick another, back to the studio. No terminal anywhere; /design floors apply.\n\nDONE WHEN: an artist rewrites a page, closes the tab, returns to the draft, round-trips it through Word, submits, and takes the next page, at desktop and phone width in light and dark. ${S}${PIXEL('Editor.dc.html')}` },
|
|
110
|
+
{ ref: 'TW11', kind: 'feature', disc: 'engineer', prio: 5, est: 240, deps: ['TW08'],
|
|
111
|
+
title: 'BV2.TW11 · /tweak skill + batch applier',
|
|
112
|
+
desc: `A new skill, /tweak: a builder or agent session takes the next submitted page, claims it, and applies every line via scripts/gds/copy-apply.js in a new --batch mode (keeps \${expr} holes; names each refusal). It renders the applied page before and after (desktop + phone, light + dark) through the ui-design kit, attaches both to the task, and parks it at waiting-for-artist (TW03). It never ships without the artist's approval (TW12).\n\nDONE WHEN: /tweak applies a multi-line page batch, attaches the renders and parks; a refused line is named, not skipped. ${S}` },
|
|
113
|
+
{ ref: 'TW12', kind: 'feature', disc: 'ui', prio: 5, est: 180, deps: ['TW11'],
|
|
114
|
+
title: 'BV2.TW12 · The Approval queue: the applied page, rendered, before and after',
|
|
115
|
+
desc: `A glass panel opened from the studio. It shows the applied page ITSELF, rendered with its new words (not a list of strings), with a before/after switch, the changed words highlighted, and the queue position ("1 of 2"). Approve and ship (the ship proceeds, the page's count goes up, the next page in the queue is named), or send it back with a one-line note (it returns to the tweak queue). Added to the studio's WRITE_ROUTES allowlist; still no live string write.\n\nDONE WHEN: approve ships the page and advances its status; send-back re-queues it with the note; both from the studio with no terminal. ${S}${PIXEL('Main.dc.html', 'its Approval queue panel')}` },
|
|
116
|
+
{ ref: 'TW13', kind: 'feature', disc: 'engineer', prio: 4, est: 150, deps: ['TW03', 'TW11'],
|
|
117
|
+
title: 'BV2.TW13 · Pay the artist for an approved page, as the artist reviews paid',
|
|
118
|
+
desc: `Owner decision: Tweak Mode replaces the per-ship artist review with the same payouts. On an approved page tweak's ship, the artist who wrote it is paid what completing the replaced artist review paid them; the applying session keeps its normal build reward. Payees resolved server-side from the task (the ADR 0185 pattern in modules/economy/credits.js), never from the caller; a self-applied tweak is one payee; the total is conserved. Feeds the studio tally (TW05).\n\nDONE WHEN: a shipped page tweak pays the artist and the applier as above, with tests for the self-applied and rounding cases. ${S}` },
|
|
119
|
+
{ ref: 'TW14', kind: 'refactor', disc: 'engineer', prio: 4, est: 150, deps: ['TW05'],
|
|
120
|
+
title: 'BV2.TW14 · Tweak Mode replaces the per-ship artist review',
|
|
121
|
+
desc: `The artist-review-on-ship cascade (modules/lifecycle/cascade.js) files one task per ship; 34 of the 39 it filed were abandoned, 33 with no note. Per TW03: a ship that changes a page's words no longer files a review task. It marks that page "changed since last tweak", which raises it in the Tweak/CopyWrite Flow and shows in Artist Review Status. Task 1004078 (the studio's review card never showing the copy) is merged into this one: with no per-ship review cards, it has nothing left to fix.\n\nDONE WHEN: a ship changing a page's text files no artist review and the page reads changed-since; the cascade's tests are updated to the new rule. ${S}` },
|
|
122
|
+
{ ref: 'TW15', kind: 'cleanup', disc: 'ui', prio: 3, est: 60, deps: ['TW16'],
|
|
123
|
+
title: 'BV2.TW15 · Archive the Copy desk and Ideas tabs',
|
|
124
|
+
desc: `Owner decision 2026-09-27: the Copy desk and the Ideas board come off the hall's tab groups. ARCHIVED, not deleted: remove both entries from the nav (modules/hall-ui/public/shell.js), keep the pages and routes reachable by link so old bookmarks and links still land, and delete no data. Ideas are still filed from Your thinking (its filing form covers quick and Full Ideas); artist work lives in the studio (TW16). Update the page-gate map and any test that pins the nav list.\n\nDONE WHEN: neither tab shows in the nav, both URLs still load, and the hall tests are green. ${S}` },
|
|
125
|
+
{ ref: 'TW20', kind: 'feature', disc: 'ui', prio: 5, est: 180, deps: [],
|
|
126
|
+
title: 'BV2.TW20 · The studio and Your thinking sit in the hall, with a full-screen switch',
|
|
127
|
+
desc: `Owner decision 2026-09-27: the Studio (/studio) and Your thinking (/thinking) join the normal hall chrome, the sidebar and the top bar, like every other hall page. Your thinking deliberately carries none today (its header comment says so). Each page gets one button that goes FULL SCREEN, hiding the sidebar and top bar so the page fills the window (the prototype's studio is what full screen looks like), and a button in full screen to come back. Shared, not per page: one switch in shell.js that any page can opt into, remembered per page in localStorage (try/catch), reachable by keyboard, with Esc leaving full screen. Both pages must still pass the kit floors in both states (header, main, 24px targets, reduced motion).\n\nDONE WHEN: both pages render inside the hall chrome, the switch hides and restores it, the choice survives a reload, and the kit floors pass in both states at 1440 and 390, light and dark. ${S}` },
|
|
128
|
+
{ ref: 'TW21', kind: 'refactor', disc: 'ui', prio: 4, est: 150, deps: ['TW20'],
|
|
129
|
+
title: 'BV2.TW21 · Your thinking is only your thinking; the project views live on the project map',
|
|
130
|
+
desc: `Owner decision 2026-09-27. Today /thinking and /goal-map are one sky with a lens switcher ("simple", "your thinking", "the whole project"); "the whole project" hands off to /goal-map, and "my ideas" lays your thoughts over the project map. Disconnect them. /thinking keeps only YOUR thinking and its own tools. The whole-project views and features, including the "the whole project" lens and the "my ideas" overlay, live only on the goals/project map page (/goal-map), which stops offering "your thinking" as a lens. Keep the shared sky-*.js code shared where it is only drawing. It is the lens and the features that separate, not the renderer.\n\nCONFIRMED BY THE OWNER (2026-09-27): "the your projects tab" means the whole-project lens, the "the whole project" switch and the project-map features on Your thinking. They move to the goals/project map page only.\n\nDONE WHEN: /thinking shows no whole-project lens or project-map features, /goal-map holds them all, neither links to the other as a lens, and the sky tests are updated to the split. ${S}` },
|
|
131
|
+
{ ref: 'TW17', kind: 'feature', disc: 'engineer', prio: 2, est: 60, deps: ['TW16'],
|
|
132
|
+
title: 'BV2.TW17 · The artist pack teaches Tweak Mode',
|
|
133
|
+
desc: `docs/packs/artist.md leads with the studio: Resume, the Tweak/CopyWrite Flow, the editor and the Word round trip, the Approval queue. The per-ship review and the copy-desk flag flow are gone from the artist's loop. Keep the pack inside its CI budget.\n\nDONE WHEN: an artist session reading only the pack can take a page through Tweak Mode. ${S}` },
|
|
134
|
+
{ ref: 'TW18', kind: 'verify', disc: 'artist', prio: 4, est: 90, deps: ['TW09', 'TW10', 'TW12', 'TW13', 'TW16'],
|
|
135
|
+
title: 'BV2.TW18 · Proof: an artist tweaks a landing page and a hall page end to end',
|
|
136
|
+
desc: `The live demonstration that wa6-tweak-mode holds. A non-technical artist, with no terminal, from the studio: takes a landing page from the Tweak/CopyWrite Flow and rewrites it in the editor, takes next and rewrites a hall page offline in Word and uploads it; a session runs /tweak; the artist approves both in the Approval queue. Both pages then read "text tweaked 1x", Artist Review Status moves, and the tally shows the payout.\n\nDONE WHEN: the above happens on the live instance and is recorded (screens + the two shipped tasks) on this task. ${S}` },
|
|
137
|
+
{ ref: 'TW19', kind: 'spike', disc: 'engineer', prio: 2, est: 120, deps: ['TW18'],
|
|
138
|
+
title: 'BV2.TW19 · Auto-pickup: an agent takes submitted tweaks with no session started',
|
|
139
|
+
desc: `"Queue now, auto later" (owner, 2026-09-27). Today agents fire only on task.shipped and may only report (modules/agents/CLAUDE.md, the event path), and the autonomy runner is off. Design an agent that claims and applies a submitted page on its own: the trigger, who pays (spend caps), the loop guard, the rank it runs at. Output: an ADR plus the tasks to build it.\n\nDONE WHEN: the ADR is written and its build tasks are filed in this goal. ${S}` },
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
// Existing task folded into the chain at TW16.
|
|
143
|
+
const TW16_TITLE = 'BV2.TW16 · ARTIST MODE: the lofi studio home, with Tweak Mode as its four doors';
|
|
144
|
+
const TW16_DESC = `RESCOPED 2026-09-27 (planning session, task 1004312; spec ${SPEC}). Task 1004238 ("the artist page is simple and lofi") is merged into this one. The photo-to-asset half split out to its own backlog task, because the core has no image path yet (see the correction in the original text below).
|
|
145
|
+
|
|
146
|
+
**Now:** the Studio (/builders/studio) becomes a lofi home an artist wants to be in. The owner likes the prototype's lofi design for now: a night window, a lamp and a desk, over the project's Chrome World tokens. On it:
|
|
147
|
+
- the studio's own words are editable in place (that edit is itself a tweak of the studio page, through TW08);
|
|
148
|
+
- the artist's tally in the top right: credits, pages tweaked, this week (TW05);
|
|
149
|
+
- **Resume** goes back into the page the artist holds (TW10);
|
|
150
|
+
- three quick actions open glass panels in place, so the artist never flips pages: **Tweak/CopyWrite Flow** (TW07), **Approval queue** (TW12) and **Artist Review Status** (TW05's three surface lines).
|
|
151
|
+
The old review/flag queue on this page goes: Tweak Mode replaces it (TW14).
|
|
152
|
+
|
|
153
|
+
DONE WHEN: an artist opening the studio can do all of Tweak Mode from it, approved by the owner at desktop and phone width in light and dark.${PIXEL('Main.dc.html')}
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
ORIGINAL DESCRIPTION (kept for provenance):
|
|
157
|
+
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
const PHOTO_TASK = {
|
|
161
|
+
kind: 'feature', disc: 'artist', prio: 2, est: 240,
|
|
162
|
+
title: 'ARTIST MODE part 2: from a photo of physical work to a usable asset',
|
|
163
|
+
desc: `Split from task 1003971 at the 2026-09-27 planning session (task 1004312). An artist uploads photos of physical work and digitises them into whatever they are meant for, keeping their personal style continuous with the project's design rules.\n\nBlocked in substance: the core has no image-generation path (modules/art-pipeline is excluded from the published core). First decide between bringing an image path into the core cleanly (its own ADR) or scoping to the parts that need no model. See 1003971's original description.\n\nNot part of the Tweak Mode chain.`,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
167
|
+
let dryId = 0;
|
|
168
|
+
async function api(method, p, body, tries = 0) {
|
|
169
|
+
if (DRY && method !== 'GET') {
|
|
170
|
+
console.log(` [dry] ${method} ${p}`);
|
|
171
|
+
return { ok: true, status: 0, json: { task: { id: `dry${++dryId}`, title: body && body.title } } };
|
|
172
|
+
}
|
|
173
|
+
await sleep(400);
|
|
174
|
+
const res = await fetch(`${BASE}/api/bongos${p}`, { method, headers: H, body: body ? JSON.stringify(body) : undefined });
|
|
175
|
+
const text = await res.text();
|
|
176
|
+
let json; try { json = JSON.parse(text); } catch { json = { _raw: text.slice(0, 300) }; }
|
|
177
|
+
if (res.status === 429 && tries < 8) {
|
|
178
|
+
const wait = ((json.error && json.error.details && json.error.details.retry_after_seconds) || 30) + 1;
|
|
179
|
+
console.log(` …rate-limited, waiting ${wait}s`);
|
|
180
|
+
await sleep(wait * 1000);
|
|
181
|
+
return api(method, p, body, tries + 1);
|
|
182
|
+
}
|
|
183
|
+
return { status: res.status, ok: res.ok, json };
|
|
184
|
+
}
|
|
185
|
+
const note = (r) => JSON.stringify(r.json).slice(0, 200);
|
|
186
|
+
|
|
187
|
+
(async () => {
|
|
188
|
+
let failed = 0;
|
|
189
|
+
const pre = await api('GET', `/goals/${GOAL}`);
|
|
190
|
+
if (!pre.ok) { console.log(`cannot read goal ${GOAL}: ${pre.status}`); cliExit(1); return; }
|
|
191
|
+
const baseline = {};
|
|
192
|
+
for (const c of pre.json.criteria || []) baseline[c.criterion_id] = Number(c.linked_tasks) || 0;
|
|
193
|
+
|
|
194
|
+
console.log('Criterion…');
|
|
195
|
+
const c = await api('POST', `/versions/${VER}/done-when`, { criterion_id: CRIT, criterion_md: CRITERION_MD, goal_id: GOAL });
|
|
196
|
+
console.log(` ${CRIT}: ${c.ok ? 'created' : c.status === 409 ? 'already seeded' : 'FAILED ' + note(c)}`);
|
|
197
|
+
if (!c.ok && c.status !== 409) { cliExit(1); return; }
|
|
198
|
+
|
|
199
|
+
console.log('Scope…');
|
|
200
|
+
const sc = await api('POST', `/goals/${GOAL}/scope`, { add: SCOPE_ADD });
|
|
201
|
+
console.log(` +${SCOPE_ADD.join(', ')}: ${sc.ok ? 'ok' : 'FAILED ' + note(sc)}`);
|
|
202
|
+
if (!sc.ok) failed++;
|
|
203
|
+
|
|
204
|
+
console.log(`Tasks (${TASKS.length})…`);
|
|
205
|
+
const idByRef = { TW16: ARTIST_MODE };
|
|
206
|
+
const plan = [];
|
|
207
|
+
for (const t of TASKS) {
|
|
208
|
+
const r = await api('POST', '/tasks', {
|
|
209
|
+
version_id: VER, goal_id: GOAL, title: t.title, description: t.desc, kind: t.kind,
|
|
210
|
+
discipline: t.disc, priority: t.prio, est_minutes: t.est, criterion_ids: [CRIT],
|
|
211
|
+
source: SRC, source_ref: `${REF}-${t.ref}`,
|
|
212
|
+
});
|
|
213
|
+
const task = r.json.task || r.json;
|
|
214
|
+
if (!r.ok || !task.id) { console.log(` ${t.ref}: FAILED ${r.status} ${note(r)}`); failed++; continue; }
|
|
215
|
+
if (!DRY && task.title !== t.title) { console.log(` ${t.ref}: source_ref collision — got task ${task.id} "${task.title}"`); failed++; continue; }
|
|
216
|
+
idByRef[t.ref] = task.id;
|
|
217
|
+
plan.push([CRIT]);
|
|
218
|
+
console.log(` ${t.ref} → task ${task.id} (${r.status})`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
console.log('Existing tasks…');
|
|
222
|
+
const am = await api('GET', `/tasks/${ARTIST_MODE}`);
|
|
223
|
+
const amTask = am.json.task || am.json;
|
|
224
|
+
if (!String(amTask.title || '').startsWith('BV2.TW16')) {
|
|
225
|
+
const r = await api('PATCH', `/tasks/${ARTIST_MODE}`, { title: TW16_TITLE, description: TW16_DESC + (amTask.description || ''), priority: 4 });
|
|
226
|
+
console.log(` 1003971 rescoped: ${r.ok ? 'ok' : 'FAILED ' + note(r)}`); if (!r.ok) failed++;
|
|
227
|
+
} else console.log(' 1003971 already rescoped');
|
|
228
|
+
const link = await api('POST', `/tasks/${ARTIST_MODE}/criteria`, { criterion_ids: [CRIT] });
|
|
229
|
+
console.log(` 1003971 → ${CRIT}: ${link.ok ? 'linked' : 'FAILED ' + note(link)}`);
|
|
230
|
+
if (link.ok) plan.push([CRIT]); else failed++;
|
|
231
|
+
for (const [from, into, why] of [
|
|
232
|
+
[LOFI_PAGE, ARTIST_MODE, 'Merged into 1003971 at the Tweak Mode planning session (task 1004312): the lofi artist page IS the rescoped ARTIST MODE studio home.'],
|
|
233
|
+
[STUDIO_COPY, idByRef.TW14, 'Merged into BV2.TW14 at the Tweak Mode planning session (task 1004312): Tweak Mode replaces the per-ship artist review, so there are no review cards left whose copy needs showing.'],
|
|
234
|
+
]) {
|
|
235
|
+
if (!into) { console.log(` ${from}: merge target missing`); failed++; continue; }
|
|
236
|
+
const mg = await api('POST', `/tasks/${from}/merge`, { into_task_id: Number(into) || into, reason: why });
|
|
237
|
+
console.log(` ${from} merged into ${into}: ${mg.ok ? 'ok' : mg.status === 409 ? 'already merged' : 'FAILED ' + note(mg)}`);
|
|
238
|
+
if (!mg.ok && mg.status !== 409) failed++;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
console.log('Dependencies…');
|
|
242
|
+
const EDGES = [...TASKS.map((t) => [t.ref, t.deps]), ['TW16', ['TW05', 'TW07', 'TW10', 'TW12', 'TW20']]];
|
|
243
|
+
for (const [ref, deps] of EDGES) {
|
|
244
|
+
if (!deps.length) continue;
|
|
245
|
+
const id = idByRef[ref];
|
|
246
|
+
const depIds = deps.map((d) => idByRef[d]).filter(Boolean);
|
|
247
|
+
if (!id || depIds.length !== deps.length) { console.log(` ${ref}: dep resolve gap`); failed++; continue; }
|
|
248
|
+
const r = await api('POST', `/tasks/${id}/dependencies`, { depends_on_task_ids: depIds });
|
|
249
|
+
console.log(` ${ref} ← ${deps.join(', ')}: ${r.ok ? 'ok' : 'FAILED ' + note(r)}`); if (!r.ok) failed++;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
console.log('Split-off task…');
|
|
253
|
+
const ph = await api('POST', '/tasks', {
|
|
254
|
+
version_id: VER, goal_id: GOAL, title: PHOTO_TASK.title, description: PHOTO_TASK.desc, kind: PHOTO_TASK.kind,
|
|
255
|
+
discipline: PHOTO_TASK.disc, priority: PHOTO_TASK.prio, est_minutes: PHOTO_TASK.est,
|
|
256
|
+
source: SRC, source_ref: `${REF}-photo-split`,
|
|
257
|
+
});
|
|
258
|
+
console.log(` photo half → ${ph.ok ? 'task ' + (ph.json.task || ph.json).id : 'FAILED ' + note(ph)}`); if (!ph.ok) failed++;
|
|
259
|
+
|
|
260
|
+
console.log('Opening the zero-dep layer…');
|
|
261
|
+
for (const ref of ['TW01', 'TW02', 'TW20']) {
|
|
262
|
+
const id = idByRef[ref]; if (!id) continue;
|
|
263
|
+
const r = await api('POST', `/tasks/${id}/promote`, {});
|
|
264
|
+
console.log(` ${ref} (task ${id}): ${r.ok ? 'ready' : 'note ' + note(r)}`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log('\nref→id:', JSON.stringify(idByRef));
|
|
268
|
+
if (DRY) return;
|
|
269
|
+
const expected = { ...baseline };
|
|
270
|
+
for (const ids of plan) for (const s of ids) expected[s] = (expected[s] || 0) + 1;
|
|
271
|
+
// A merge abandons its task, and 1004078 was linked to other criteria on this
|
|
272
|
+
// goal; if the goal's linked_tasks counts only live tasks, that criterion drops
|
|
273
|
+
// by one. Report it rather than fail on it.
|
|
274
|
+
await verifySeedCriteriaLinks({ goalId: GOAL, expectedCounts: expected, fetchGoal: (id) => api('GET', `/goals/${id}`),
|
|
275
|
+
exit: (code) => { if (code) console.log('(check the mismatch above: a drop of 1 on a criterion 1004078 or 1004238 was linked to is the merge, not a mislink)'); failed += code ? 1 : 0; } });
|
|
276
|
+
if (failed) { console.log(`${failed} step(s) FAILED — see above.`); cliExit(1); }
|
|
277
|
+
})();
|
package/scripts/setup-builder.sh
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
#
|
|
4
4
|
# The bootstrap logic now lives in scripts/setup-builder.js (Node), so it runs
|
|
5
5
|
# on Windows/macOS/Linux alike. This shim stays so existing references keep
|
|
6
|
-
# working on Mac/Linux — README
|
|
7
|
-
#
|
|
8
|
-
#
|
|
6
|
+
# working on Mac/Linux — README and the onboarding primer invoke
|
|
7
|
+
# `./scripts/setup-builder.sh` / `bash scripts/setup-builder.sh ...`. It simply
|
|
8
|
+
# forwards all arguments to the Node script.
|
|
9
9
|
#
|
|
10
10
|
# On Windows (no Git Bash), run the Node entry directly instead:
|
|
11
11
|
# node scripts/setup-builder.js [--skip-keys] [--no-auth] [--help]
|
|
@@ -404,27 +404,14 @@ const MODULE_GLOBS = {
|
|
|
404
404
|
// The SELF-HOST IMAGE (V4.R63, task 1202, ADR 0062): `docker compose up` brings
|
|
405
405
|
// up Postgres + a vanilla, neutral-branded instance with every feature module
|
|
406
406
|
// off. Assigned here by task 1004146 — same class as the .github/ and .husky/
|
|
407
|
-
// entries above
|
|
408
|
-
// defines WHAT RUNS. Not
|
|
407
|
+
// entries above: repo-root build config that defines WHAT RUNS. Not
|
|
409
408
|
// `provisioning`, which owns the control plane that stands up instances, not an
|
|
410
|
-
// image a stranger runs.
|
|
411
|
-
// inbound references coming from .devcontainer/ and the devcontainer workflow.
|
|
409
|
+
// image a stranger runs.
|
|
412
410
|
'Dockerfile', 'docker-compose.yml', 'docker-entrypoint.sh', '.dockerignore',
|
|
413
411
|
// Repo-level dotfiles, the class .gitattributes and .npmrc already sit in.
|
|
414
412
|
// .env.local.example is the local-secrets template, next to the .gitleaks.toml
|
|
415
413
|
// scanner config above (task 1004146).
|
|
416
414
|
'.gitignore', '.env.local.example',
|
|
417
|
-
// .devcontainer/ is the same class as the entries above it — repo-level
|
|
418
|
-
// developer-environment config, not a feature's territory (task 1004029).
|
|
419
|
-
// It belonged to NO module and was not in SHARED_GLOBS, so isCovered() said
|
|
420
|
-
// false for it under EVERY possible scope_modules value: no goal could
|
|
421
|
-
// authorize a task that touched it, which is what stalled task 1003896
|
|
422
|
-
// (delete .devcontainer/). Given to devsecops rather than added to
|
|
423
|
-
// SHARED_GLOBS because it has a real owner — SHARED_GLOBS is for roots owned
|
|
424
|
-
// by nobody, and every addition there widens the wall for every goal at once.
|
|
425
|
-
// devsecops is PROTECTED, so this path is now Archon-only to scope; that is
|
|
426
|
-
// the correct floor for a file that defines what a builder's environment runs.
|
|
427
|
-
'.devcontainer/',
|
|
428
415
|
'package.json', 'package-lock.json',
|
|
429
416
|
'scripts/gds/fitness.js', 'scripts/gds/docs-entropy.js',
|
|
430
417
|
'scripts/gds/redteam-patrol.js', 'scripts/gds/audit-gate.js',
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.1051'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|