@bongos/core 1.19.546 → 1.19.547
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.bongos-core.json
CHANGED
|
@@ -2,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.547",
|
|
6
|
+
"core_contract": "1.19.547",
|
|
7
|
+
"source_commit": "74fc01314b948646eac524ea4ffe8379166aa924",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-04T18:
|
|
9
|
+
"built_at": "2026-09-04T18:16:19.583Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 441,
|
|
13
13
|
"agent_docs_stubbed": 24,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2013,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2478,
|
|
20
|
+
"tree_sha256": "7920af699f6e91dc4611edbd8cd050bd7865d5a8bb94cf035bdfb02b122664f3",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -2647,7 +2647,7 @@
|
|
|
2647
2647
|
{
|
|
2648
2648
|
"path": "docs/module-api-changelog.md",
|
|
2649
2649
|
"mode": "0000644",
|
|
2650
|
-
"sha256": "
|
|
2650
|
+
"sha256": "6410d7bb5a2067929dde46c0a7e263399cb8dc23e86379fa745b295c93a152c5"
|
|
2651
2651
|
},
|
|
2652
2652
|
{
|
|
2653
2653
|
"path": "docs/modules-contract.md",
|
|
@@ -7452,12 +7452,12 @@
|
|
|
7452
7452
|
{
|
|
7453
7453
|
"path": "package-lock.json",
|
|
7454
7454
|
"mode": "0000644",
|
|
7455
|
-
"sha256": "
|
|
7455
|
+
"sha256": "edfd30e60e4310548e2c7e53e1b6b4a417274946420ae9ae4750d0e84761d063"
|
|
7456
7456
|
},
|
|
7457
7457
|
{
|
|
7458
7458
|
"path": "package.json",
|
|
7459
7459
|
"mode": "0000644",
|
|
7460
|
-
"sha256": "
|
|
7460
|
+
"sha256": "62c9b3498ca825e2fc22c2f3ff0105a2b59cf99d12603c18b8d2762e64d38d46"
|
|
7461
7461
|
},
|
|
7462
7462
|
{
|
|
7463
7463
|
"path": "public-docs/index.html",
|
|
@@ -8459,6 +8459,11 @@
|
|
|
8459
8459
|
"mode": "0000644",
|
|
8460
8460
|
"sha256": "e31e05399aef47863e1f74ecdd8ceaba9218e8995a8b45c7247ffae2e3ee23ea"
|
|
8461
8461
|
},
|
|
8462
|
+
{
|
|
8463
|
+
"path": "scripts/gds/seed-strict-versioning-tasks.js",
|
|
8464
|
+
"mode": "0000644",
|
|
8465
|
+
"sha256": "66d8b5c453a091bf00d43f012d1bddd6d994f8ad744c59eb7b02234846778e46"
|
|
8466
|
+
},
|
|
8462
8467
|
{
|
|
8463
8468
|
"path": "scripts/gds/seed-v2-world-tasks.js",
|
|
8464
8469
|
"mode": "0000644",
|
|
@@ -9142,7 +9147,7 @@
|
|
|
9142
9147
|
{
|
|
9143
9148
|
"path": "src/module-api.js",
|
|
9144
9149
|
"mode": "0000644",
|
|
9145
|
-
"sha256": "
|
|
9150
|
+
"sha256": "2aae43b72235b33a2f8c641093400a69f921043593bffa26e6f421fb4a9e9131"
|
|
9146
9151
|
},
|
|
9147
9152
|
{
|
|
9148
9153
|
"path": "src/module-loader/catalog.js",
|
|
@@ -1541,5 +1541,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1541
1541
|
landed since 1.19.544 with no explicit bump. run 33902527608. (task 1002620)
|
|
1542
1542
|
1.19.546 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1543
1543
|
landed since 1.19.545 with no explicit bump. run 33904396127. (task 1002620)
|
|
1544
|
+
1.19.547 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1545
|
+
landed since 1.19.546 with no explicit bump. run 33904937499. (task 1002620)
|
|
1544
1546
|
---------------------------------------------------------------------------
|
|
1545
1547
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.547",
|
|
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.547",
|
|
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.547",
|
|
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",
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/gds/seed-strict-versioning-tasks.js — seeds goal 1000086 ("Strict
|
|
3
|
+
// versioning: a goal cannot outlive its tasks") from the spec at
|
|
4
|
+
// docs/specs/bongos-v1-strict-versioning.md. Idempotent on source_ref, throttled
|
|
5
|
+
// against the per-IP write limiter, and self-verifying: the last step diffs the
|
|
6
|
+
// criterion links that actually landed against the plan and exits non-zero on
|
|
7
|
+
// any drift (task 1003076).
|
|
8
|
+
|
|
9
|
+
const { execFile } = require('child_process');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { expectedCriterionCounts, verifySeedCriteriaLinks } = require('./seed-verify-criteria');
|
|
12
|
+
|
|
13
|
+
const VERSION = 'BONGOS-V1';
|
|
14
|
+
const GOAL = 1000086;
|
|
15
|
+
const PREFIX = 'strict-versioning';
|
|
16
|
+
const API = path.join(__dirname, 'api.js');
|
|
17
|
+
const WRITE_DELAY_MS = 4200;
|
|
18
|
+
|
|
19
|
+
const C1 = 'sv-goal-set-closed';
|
|
20
|
+
const C2 = 'sv-goal-outlives-nothing';
|
|
21
|
+
const C3 = 'sv-killing-a-goal-is-deliberate';
|
|
22
|
+
const C4 = 'sv-every-task-has-a-goal';
|
|
23
|
+
const C5 = 'sv-a-version-can-close';
|
|
24
|
+
const C6 = 'sv-one-train-per-project';
|
|
25
|
+
const C7 = 'sv-cutover-proven-live';
|
|
26
|
+
|
|
27
|
+
// TASKS — ref is the V##.R## rank suffix; deps are refs resolved to real task
|
|
28
|
+
// ids after every task exists. Descriptions stay short and cross-reference by
|
|
29
|
+
// ref rather than restating the spec (which is the durable context).
|
|
30
|
+
const TASKS = [
|
|
31
|
+
{
|
|
32
|
+
ref: 'R01', kind: 'refactor', priority: 5, est: 90, criteria: [C2], deps: [],
|
|
33
|
+
title: 'BV1.R01 — One terminal-status vocabulary: shipped or abandoned, declared once',
|
|
34
|
+
desc: '`goal-rollup.js:37` counts shipped|confirmed|completed as done; `done-when.js:429` counts only shipped and treats abandoned as accounted-for. Two definitions of "finished" in one module is what lets a goal read closed on one surface and open on another. Declare the terminal set once and have both read it.\n\n**Done when:** a single exported constant is the only spelling of the terminal set; `goal-rollup.js` and `done-when.js` both consume it; `tests/goal_sort_staleness.mjs` (which pins the rollup against the client `goals-lib.js`) still passes, or is updated with the reason.',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
ref: 'R02', kind: 'decision', priority: 5, est: 120, criteria: [C1], deps: [],
|
|
38
|
+
title: 'BV1.R02 — ADR: strict versioning — the version boundary is the scope gate',
|
|
39
|
+
desc: 'Write the ADR behind goal 1000086. Records the model: goals are scoped onto a `planning` version, the goal set closes when the version starts building, an Archon override admits a named goal with a reason, a goal cannot close while it holds non-terminal work, and exactly one version builds per project. Cite the measured state that motivated it (62 goals, 10 closed while holding 28 open tasks, 502 open tasks across 37 open goals, two building versions on one project).\n\n**Done when:** the ADR exists, is indexed in `docs/adr/README.md`, and is linked from goal 1000086. Take the next free ADR number immediately before pushing — concurrent agents collide on it.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
ref: 'R05', kind: 'feature', priority: 5, est: 90, criteria: [C4], deps: [],
|
|
43
|
+
title: 'BV1.R05 — POST /tasks and PATCH /tasks/:id read goal.status',
|
|
44
|
+
desc: '`POST /goals/:id/tasks` already refuses a non-open goal (`goal-route-authz.js:47`, 409 `goal_not_open`), but `POST /tasks` (`task-write-routes.js:167`) and `PATCH /tasks/:id` (`:392`) validate only that the goal exists and belongs to the version. A task can be created directly into an achieved or archived goal today. Close the asymmetry.\n\n**Done when:** both vectors refuse a non-open goal with the same named 409 the goal-scoped route uses; a test covers each vector.',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
ref: 'R03', kind: 'feature', priority: 5, est: 120, criteria: [C1], deps: ['R02'],
|
|
48
|
+
title: 'BV1.R03 — POST /goals refuses a version that is not in planning',
|
|
49
|
+
desc: '`routes/goals.js:101` fetches the version row and discards it after the null check — `version.status` is never read, so a goal can be created on a shipped version. Add the gate: goals may be created on a `planning` version (that is where the next version is scoped in advance); a `building` version refuses without the R07 override.\n\n**Done when:** a pure `authorizeGoalCreate` lives beside `authorizeGoalTaskCreate` in `goal-route-authz.js` and is unit-tested DB-free; the refusal is a named 409 an agent can act on; reuse `versionAcceptsNewWork`\'s status vocabulary rather than respelling it.',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
ref: 'R04', kind: 'feature', priority: 5, est: 90, criteria: [C1], deps: ['R02'],
|
|
53
|
+
title: 'BV1.R04 — POST /versions refuses a second planning version for a project',
|
|
54
|
+
desc: 'With R03 in place, a builder blocked from adding a goal to the building version could cut a second planning version and put it there. One planning version per project means exactly one queue for future goals and no parallel escape hatches.\n\n**Done when:** `POST /versions` returns a named 409 when a planning version already exists for the project; a test covers it.',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
ref: 'R06', kind: 'spike', priority: 5, est: 180, criteria: [C5], deps: ['R02'],
|
|
58
|
+
title: 'BV1.R06 — Design pass: how a version closes (auto, early, roll-forward, maintenance exemption)',
|
|
59
|
+
desc: 'No route ships a version — `scripts/gds/version-close.js:290` prints that the API exposes no version status transitions, and the flip is hand-run SQL on the droplet. The `version.close` permission exists at the archon floor (`government/catalog.js:103`) and nothing references it. Design the lifecycle before building it: auto-close when the last non-maintenance goal achieves, Archon early-close with a per-goal disposition, roll-forward via `succeeds_goal_id` lineage, and the maintenance goal\'s exemption from the close count. Reuse `version-close.js:66` `suggestClose` and `getCarryOverCount` — the judgement already exists and is merely advisory.\n\n**Done when:** an ADR states the model and the sub-tasks it implies are filed. Spike — will not auto-promote; open it manually.',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
ref: 'R07', kind: 'feature', priority: 5, est: 150, criteria: [C1], deps: ['R03'],
|
|
63
|
+
title: 'BV1.R07 — Archon override: admit one named goal to a building version, with a reason',
|
|
64
|
+
desc: 'The escape valve for R03. An Archon may admit a specific net-new goal into an in-flight version and must record why. Per-goal, never a blanket unlock.\n\n**Done when:** an override row stores the goal, the actor, the reason and the timestamp; only an Archon can create one; a goal admitted this way is created normally in every other respect.',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
ref: 'R08', kind: 'feature', priority: 5, est: 120, criteria: [C2], deps: ['R01'],
|
|
68
|
+
title: 'BV1.R08 — achieveGoalIfComplete refuses a goal that still holds non-terminal tasks',
|
|
69
|
+
desc: '`db-goals.js:193-213` decides achievement from `done_when_criteria` alone; tasks are never queried. A goal whose criteria are all satisfied auto-achieves while holding any number of backlog or ready tasks, because those tasks are linked to no criterion. Add the second condition to the manual-satisfy path.\n\n**Done when:** the check uses R01\'s terminal set; a goal holding a ready/backlog/blocked/active/completed/confirmed task cannot reach achieved via `POST /done-when/:id/satisfy`.',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
ref: 'R09', kind: 'feature', priority: 5, est: 120, criteria: [C2], deps: ['R01'],
|
|
73
|
+
title: 'BV1.R09 — The achievement cascade gains the same check, on the caller exec',
|
|
74
|
+
desc: 'The sibling of R08 in `done-when.js:451-460` — the cascade inside `autoSatisfyShippedCriteria`, which is the path that actually fires on every ship (`db-ship.js:434`) and every reconciler tick (`publish-reconciler.js:847`). It is a deliberate duplicate of the `db-goals.js` rule (collapsing them creates a require cycle), so both must change or neither does.\n\n**Done when:** the same predicate is a third NOT EXISTS clause on the cascade UPDATE, run on `exec` and never the module pool, so the ship transaction sees its own uncommitted flips. Shipping itself must remain unblocked — only the goal flip is gated.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
ref: 'R10', kind: 'feature', priority: 5, est: 120, criteria: [C3], deps: ['R01'],
|
|
78
|
+
title: 'BV1.R10 — Archive previews its open tasks and refuses without a disposition',
|
|
79
|
+
desc: '`POST /goals/:id/archive` (`routes/goals.js:1043`) refuses only if the goal is already archived — no criterion check, no task check. It is the hole that bypasses R08/R09 entirely, and how goal 1000018 was archived with all 7 tasks still open. Archiving a goal that holds open work must first return that work.\n\n**Done when:** archiving a goal with non-terminal tasks returns them and a named 409; archiving one with none stays a single call.',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
ref: 'R11', kind: 'feature', priority: 5, est: 150, criteria: [C4], deps: ['R05'],
|
|
83
|
+
title: 'BV1.R11 — goal_id becomes required; delete the catch-all fallback',
|
|
84
|
+
desc: '`db-tasks.js:150` silently falls back to `generalGoalIdForVersion` when no goal is named, and the two resulting catch-alls hold 53 open tasks. Goal-less work is the hole through which unscoped work accumulates invisibly.\n\n**Done when:** `POST /tasks` requires `goal_id`; the fallback is deleted; every in-repo caller passes a goal. R25 drains the existing catch-alls.',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
ref: 'R12', kind: 'feature', priority: 5, est: 180, criteria: [C5], deps: ['R06'],
|
|
88
|
+
title: 'BV1.R12 — POST /versions/:id/close, behind the version.close permission',
|
|
89
|
+
desc: 'Build what R06 designed. Archon-only, wired to the already-defined `version.close` permission. Any goal still open at close time takes an explicit decision — roll forward (R17) or abandon.\n\n**Done when:** the route exists, refuses a non-Archon, refuses an early close that leaves a goal without a disposition, and sets `shipped_at`.',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
ref: 'R13', kind: 'verify', priority: 4, est: 150, criteria: [C2], deps: ['R08', 'R09'],
|
|
93
|
+
title: 'BV1.R13 — Goal-closure invariant suite',
|
|
94
|
+
desc: 'Pin the C2 invariant across both writers so it cannot regress the way the two vocabularies drifted apart.\n\n**Done when:** tests cover the manual-satisfy path (R08) and the cascade (R09); one test proves the cascade sees the ship transaction\'s uncommitted flip; one test proves a ship still lands while its goal is held open by a sibling backlog task; the existing `goal_achievement.mjs`, `auto_satisfy_criteria.mjs` and `criterion_progress.mjs` all still pass.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
ref: 'R14', kind: 'feature', priority: 4, est: 180, criteria: [C3], deps: ['R10'],
|
|
98
|
+
title: 'BV1.R14 — Archive applies the disposition: abandon with a reason, or move to a named goal',
|
|
99
|
+
desc: 'The second half of R10. The caller re-submits naming what happens to each open task; nothing is discarded without a decision, which was the owner\'s explicit constraint.\n\n**Done when:** each task is either abandoned (stamped with the archive reason) or moved to a named surviving goal; the disposition is recorded per task; the goal ends archived holding zero non-terminal tasks.',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
ref: 'R15', kind: 'feature', priority: 4, est: 120, criteria: [C1], deps: ['R07'],
|
|
103
|
+
title: 'BV1.R15 — Overrides are countable and visible on the version',
|
|
104
|
+
desc: 'An override nobody can count is indistinguishable from no gate at all. Surface them so abuse is measurable.\n\n**Done when:** the version rollup exposes the override count; the hall shows which goals were admitted mid-version, by whom, and why.',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
ref: 'R16', kind: 'feature', priority: 4, est: 150, criteria: [C5], deps: ['R12', 'R08', 'R09'],
|
|
108
|
+
title: 'BV1.R16 — A version closes itself when its last non-maintenance goal achieves',
|
|
109
|
+
desc: 'The automatic finish line. Fires from the goal-achievement path (R08/R09), skipping the maintenance goal (R18) — without that exemption a version can never auto-close, because the maintenance goal is open by design.\n\n**Done when:** achieving the last non-exempt goal flips the version to closed; a version whose only open goal is the maintenance goal closes; the auto-promotion of the next version (R20) fires from the same event.',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
ref: 'R17', kind: 'feature', priority: 4, est: 150, criteria: [C5], deps: ['R12'],
|
|
113
|
+
title: 'BV1.R17 — Roll-forward: an unfinished goal becomes a successor goal in the next version',
|
|
114
|
+
desc: 'The sanctioned exit for a goal that is not done when its version closes. `POST /goals` already accepts `succeeds_goal_id` and stamps the predecessor\'s `succeeded_by_goal_id` (`routes/goals.js:108,130`) — reuse it rather than inventing a second lineage.\n\n**Done when:** rolling a goal forward creates the successor in the target version with its open tasks, sets both lineage pointers, and archives the predecessor; the chain is queryable across versions.',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
ref: 'R18', kind: 'feature', priority: 4, est: 180, criteria: [C6], deps: ['R06', 'R12'],
|
|
118
|
+
title: 'BV1.R18 — The maintenance goal: auto-created per version, exempt from close, carries bugs forward',
|
|
119
|
+
desc: 'Where a defect against already-shipped work lands. Auto-created with each version, flagged exempt so it never blocks the auto-close count, and on close its unfinished bugs move to the successor version\'s maintenance goal. The one goal that legitimately spans versions.\n\n**Done when:** creating a version creates its maintenance goal; the exempt flag is read by R16; close carries the open bugs forward; the goal is otherwise an ordinary goal.',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
ref: 'R19', kind: 'feature', priority: 4, est: 90, criteria: [C6], deps: ['R04'],
|
|
123
|
+
title: 'BV1.R19 — Refuse a second building version for a project',
|
|
124
|
+
desc: 'BONGOS-V1 and CB-V1 are both building on the same project today, which is why "the current version" has no meaning and R03\'s gate would have two answers. This is the invariant every other rule depends on.\n\n**Done when:** the server refuses to put a second version into `building` for a project; a named 409; a test covers it. R27 resolves the existing violation.',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
ref: 'R20', kind: 'feature', priority: 4, est: 120, criteria: [C6], deps: ['R12', 'R19'],
|
|
128
|
+
title: 'BV1.R20 — The planning version promotes itself when the building version closes',
|
|
129
|
+
desc: 'Keeps the "exactly one building version" invariant machine-maintained and leaves no window where the project has no live train and nothing is claimable.\n\n**Done when:** closing the building version flips the single planning version to building in the same transaction; with no planning version, close still succeeds and the project is simply idle.',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
ref: 'R21', kind: 'feature', priority: 4, est: 90, criteria: [C6], deps: ['R04'],
|
|
133
|
+
title: 'BV1.R21 — Raise version.create back to the Archon floor',
|
|
134
|
+
desc: 'ADR 0157 delegated `version.create` to Metic. Once the version boundary gates all scope (R03), the power to cut a version is the power to bypass every gate in this design.\n\n**Done when:** the catalog floor is archon; an ADR records the partial reversal of ADR 0157 and its reason; `/planning-session` and `/goal-create` docs reflect the new floor.',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
ref: 'R22', kind: 'feature', priority: 4, est: 120, criteria: [C4], deps: ['R11'],
|
|
138
|
+
title: 'BV1.R22 — Capture and idea-routing vectors name a goal',
|
|
139
|
+
desc: 'With R11 landed, any vector that creates a task without a goal simply breaks. `routeIdeaToGoal` (`modules/ideas/inbox.js:328`) already requires an open goal on a building version; `capture.js` and the other creation paths need the same discipline.\n\n**Done when:** every in-repo task-creation vector names a goal or fails loudly with an actionable message; no path silently produces an orphan.',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
ref: 'R23', kind: 'cleanup', priority: 4, est: 60, criteria: [C5], deps: ['R12'],
|
|
143
|
+
title: 'BV1.R23 — version-close.js drives the route instead of printing that the API cannot',
|
|
144
|
+
desc: '`scripts/gds/version-close.js:290` tells the operator the API exposes no version status transitions and to run SQL on the droplet. After R12 that text is false and the SQL path is the bypass.\n\n**Done when:** the script calls `POST /versions/:id/close`; the droplet-SQL instruction is deleted; the advisory `suggestClose` output is kept.',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
ref: 'R24', kind: 'feature', priority: 3, est: 150, criteria: [C3], deps: ['R14'],
|
|
148
|
+
title: 'BV1.R24 — Hall surface: the archive two-step, and why a goal is held open',
|
|
149
|
+
desc: 'The gates are only usable if a builder can see what is holding a goal open before they try to close it, and can walk the archive disposition without curl.\n\n**Done when:** a goal page shows the non-terminal tasks blocking its closure; the archive flow presents the preview and collects the disposition; both follow the hall\'s existing row idioms.',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
ref: 'R25', kind: 'cleanup', priority: 4, est: 180, criteria: [C4], deps: ['R11', 'R14'],
|
|
153
|
+
title: 'BV1.R25 — Rehome the 53 catch-all tasks; drain and archive both catch-alls',
|
|
154
|
+
desc: 'Goal 1000003 ("Work with no goal yet") holds 37 open tasks and CB-V1\'s general goal holds 16. Under R11 no new ones can appear; these are the existing population.\n\n**Done when:** every one of the 53 is moved to a real goal or abandoned with a reason via R14\'s flow; both catch-alls hold zero tasks and are archived; a query proving zero catch-all tasks is captured in the notes.',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
ref: 'R26', kind: 'cleanup', priority: 4, est: 180, criteria: [C7], deps: ['R14'],
|
|
158
|
+
title: 'BV1.R26 — Disposition the 10 closed goals that still hold 28 open tasks',
|
|
159
|
+
desc: 'The existing violations of C2, measured 2026-09-04: goals 1000018 (archived, all 7 tasks open), 1000072 (achieved, 7), 1000051 (4), 1000041 (3), 1000060 (2), 1000031, 1000034, 1000056, 1000061, 1000071 (1 each). Walk each through R14\'s preview-and-dispose flow so the new rule starts from a true state.\n\n**Done when:** all 28 are moved or abandoned with a reason; a query returns zero closed goals holding non-terminal tasks.',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
ref: 'R27', kind: 'infra', priority: 4, est: 180, criteria: [C7], deps: ['R12', 'R17'],
|
|
163
|
+
title: 'BV1.R27 — Fold CB-V1 into BONGOS-V1 and close CB-V1',
|
|
164
|
+
desc: 'CB-V1 is the same project as BONGOS-V1 ("CB" is Cloud Bongos), and both are building — the violation R19 forbids. Its 4 open goals (1000043, 1000066, 1000084 and its general catch-all) move to BONGOS-V1; its 2 achieved goals stay with the closed version.\n\n**Done when:** the open goals are in BONGOS-V1 with lineage intact; CB-V1 is closed via R12; its 98 non-terminal tasks are all accounted for under a real goal; exactly one version is building.',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
ref: 'R28', kind: 'decision', priority: 4, est: 120, criteria: [C7], deps: ['R27', 'R26'],
|
|
168
|
+
title: 'BV1.R28 — Owner names the goals that ARE BONGOS-V1; everything else moves to V2',
|
|
169
|
+
desc: 'Measured during the planning session: a 14-day activity window keeps 28 of 37 open goals and 454 of 502 open tasks in V1 — nothing is stale because the instance is busy, so no mechanical rule produces a finish line. The owner names the handful of goals that define what V1 means (target ~5-8); every other open goal is targeted at BONGOS-V2 regardless of activity.\n\n**Done when:** the list is recorded in the task notes with each goal\'s open-task count; every open goal is labelled stay or move. Needs the owner — file a blocker if it stalls.',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
ref: 'R29', kind: 'feature', priority: 4, est: 180, criteria: [C7], deps: ['R28', 'R03'],
|
|
173
|
+
title: 'BV1.R29 — Scope BONGOS-V2 in planning, with its goal set and criteria',
|
|
174
|
+
desc: 'The first version created under the new rules, and the proof that scoping-before-building works. Created in `planning` so its goals can be authored (R03), holding every goal R28 marked move.\n\n**Done when:** BONGOS-V2 exists in `planning`; the moved goals are on it as successors with lineage; every goal on it has at least one done-when criterion; it is the only planning version.',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
ref: 'R30', kind: 'verify', priority: 4, est: 120, criteria: [C7], deps: ['R29', 'R25', 'R20', 'R13'],
|
|
178
|
+
title: 'BV1.R30 — Proof: the four invariants hold on the live instance',
|
|
179
|
+
desc: 'The single live demonstration that goal 1000086 is met. Run each query against live and capture its output verbatim in the task notes:\n1. zero goals in achieved/archived holding a task that is not shipped or abandoned;\n2. zero tasks in a catch-all goal, and zero tasks with a null goal;\n3. exactly one version in `building` for the project, and at most one in `planning`;\n4. BONGOS-V2 exists in `planning` with criteria on every goal.\nThen attempt one refusal of each gate (add a goal to the building version; close a goal holding a backlog task; archive without a disposition) and record the 409s.\n\n**Done when:** all four queries return the expected result and all three refusals fire, with transcripts in the notes.',
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
function api(method, route, body) {
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
const args = [API, method, route];
|
|
186
|
+
if (body) args.push('--body', JSON.stringify(body));
|
|
187
|
+
execFile('node', args, { maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
188
|
+
const raw = String(stdout || '');
|
|
189
|
+
const start = raw.indexOf('{');
|
|
190
|
+
let json = null;
|
|
191
|
+
if (start >= 0) { try { json = JSON.parse(raw.slice(start)); } catch { /* non-JSON body */ } }
|
|
192
|
+
const status = Number((String(stderr || '') + raw).match(/→ (\d{3})/)?.[1] || 0);
|
|
193
|
+
if (err && !json) return reject(new Error(`${method} ${route} failed: ${err.message}\n${stderr}`));
|
|
194
|
+
resolve({ ok: status >= 200 && status < 300, status, json });
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
200
|
+
|
|
201
|
+
// throttledWrite — the per-IP limiter kills a long seed halfway unless each
|
|
202
|
+
// write is paced and a 429 backs off on the server's own retry_after.
|
|
203
|
+
async function throttledWrite(method, route, body) {
|
|
204
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
205
|
+
const r = await api(method, route, body);
|
|
206
|
+
if (r.status === 429) {
|
|
207
|
+
// The limiter answers res.fail('rate_limited', 429, {scope, retry_after_seconds}),
|
|
208
|
+
// and the error envelope nests that payload under error.details — same path
|
|
209
|
+
// seed-bongos-v1-idea-routing-tasks.js reads. Any other spelling silently
|
|
210
|
+
// falls back to the default and ignores the server's computed wait.
|
|
211
|
+
const wait = (Number(r.json?.error?.details?.retry_after_seconds) || 30) * 1000 + 1000;
|
|
212
|
+
console.log(` 429 — backing off ${wait}ms`);
|
|
213
|
+
await sleep(wait);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
await sleep(WRITE_DELAY_MS);
|
|
217
|
+
return r;
|
|
218
|
+
}
|
|
219
|
+
throw new Error(`${method} ${route} still rate-limited after 5 attempts`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// The meta planning task (1003586) was created before this seed ran and links
|
|
223
|
+
// to C1. It is a real link on the goal, so the plan must count it or the
|
|
224
|
+
// verification below reports a false mismatch.
|
|
225
|
+
const PRE_EXISTING_LINKS = [[C1]];
|
|
226
|
+
|
|
227
|
+
async function main() {
|
|
228
|
+
const ids = {};
|
|
229
|
+
const planned = [...PRE_EXISTING_LINKS];
|
|
230
|
+
|
|
231
|
+
console.log(`Seeding ${TASKS.length} tasks into goal ${GOAL} (${VERSION})\n`);
|
|
232
|
+
|
|
233
|
+
for (const t of TASKS) {
|
|
234
|
+
const body = {
|
|
235
|
+
version_id: VERSION,
|
|
236
|
+
goal_id: GOAL,
|
|
237
|
+
title: t.title,
|
|
238
|
+
description: t.desc,
|
|
239
|
+
kind: t.kind,
|
|
240
|
+
discipline: 'engineer',
|
|
241
|
+
priority: t.priority,
|
|
242
|
+
est_minutes: t.est,
|
|
243
|
+
source: 'planning-session',
|
|
244
|
+
source_ref: `${PREFIX}-${t.ref}`,
|
|
245
|
+
criterion_ids: t.criteria,
|
|
246
|
+
};
|
|
247
|
+
const r = await throttledWrite('POST', '/api/gds/tasks', body);
|
|
248
|
+
const id = r.json?.task?.id;
|
|
249
|
+
if (!id) throw new Error(`No task id back for ${t.ref} (status ${r.status}): ${JSON.stringify(r.json)}`);
|
|
250
|
+
ids[t.ref] = id;
|
|
251
|
+
planned.push(t.criteria);
|
|
252
|
+
console.log(` ${t.ref} -> task ${id} [${t.criteria.join(',')}] ${r.status}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
console.log('\nWiring dependencies...');
|
|
256
|
+
for (const t of TASKS) {
|
|
257
|
+
for (const dep of t.deps) {
|
|
258
|
+
if (!ids[dep]) throw new Error(`${t.ref} depends on unknown ref ${dep}`);
|
|
259
|
+
const r = await throttledWrite('POST', `/api/gds/tasks/${ids[t.ref]}/dependencies`, { depends_on_task_id: ids[dep] });
|
|
260
|
+
console.log(` ${t.ref} depends on ${dep} (${ids[dep]}) ${r.status}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log('\nVerifying criterion links landed as planned...');
|
|
265
|
+
await verifySeedCriteriaLinks({
|
|
266
|
+
goalId: GOAL,
|
|
267
|
+
expectedCounts: expectedCriterionCounts(planned),
|
|
268
|
+
fetchGoal: (goalId) => api('GET', `/api/gds/goals/${goalId}`),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
console.log('\nSeed complete. Task ids:');
|
|
272
|
+
for (const t of TASKS) console.log(` ${t.ref} = ${ids[t.ref]}`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
main().catch((e) => { console.error(e.message); process.exit(1); });
|
package/src/module-api.js
CHANGED
|
@@ -49,7 +49,7 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
49
49
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
50
50
|
// the entry to that file. Look for a version's history there, not here.
|
|
51
51
|
// ---------------------------------------------------------------------------
|
|
52
|
-
const CORE_VERSION = '1.19.
|
|
52
|
+
const CORE_VERSION = '1.19.547'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
53
53
|
|
|
54
54
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
55
55
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|