@bongos/core 1.19.332 → 1.19.333
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 +160 -40
- package/docs/api/openapi.json +2 -2
- package/docs/api-reference.md +1 -1
- package/docs/copy-inventory.md +202 -202
- package/docs/copy-registry.json +384 -384
- package/modules/grading/grader-config.js +98 -0
- package/modules/grading/grader-model.js +150 -0
- package/modules/grading/grader-prompt.js +139 -0
- package/modules/grading/grader-score.js +706 -0
- package/modules/grading/grader-subagent.js +328 -0
- package/modules/grading/grader.js +5 -1287
- package/modules/hall-ui/public/builders.js +19 -1182
- package/modules/hall-ui/public/goals-page.js +11 -997
- package/modules/hall-ui/public/goals-render.js +1032 -0
- package/modules/hall-ui/public/goals.html +4 -0
- package/modules/hall-ui/public/hall-render.js +1211 -0
- package/modules/hall-ui/public/index.html +6 -0
- package/modules/lifecycle/routes/goal-route-authz.js +400 -0
- package/modules/lifecycle/routes/goals.js +1 -367
- package/modules/lifecycle/routes/task-route-helpers.js +219 -0
- package/modules/lifecycle/routes/task-write-routes.js +542 -0
- package/modules/lifecycle/routes/tasks.js +3 -696
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/box-infra.js +280 -0
- package/scripts/gds/box.js +1 -245
- package/scripts/gds/fitness-checks-identity.js +320 -0
- package/scripts/gds/fitness-checks-vocabulary.js +230 -0
- package/scripts/gds/fitness-checks-write-validation.js +144 -0
- package/scripts/gds/fitness-lib.js +82 -0
- package/scripts/gds/fitness.js +55 -668
- package/scripts/gds/provision-config.js +204 -0
- package/scripts/gds/provision-net.js +221 -0
- package/scripts/gds/provision-repo.js +849 -0
- package/scripts/gds/provision-units.js +262 -0
- package/scripts/gds/provision.js +4 -1395
- package/src/bongos/auth-admission.js +264 -0
- package/src/bongos/auth-config.js +151 -0
- package/src/bongos/auth-discord.js +198 -0
- package/src/bongos/auth-github.js +336 -0
- package/src/bongos/auth-idp.js +330 -0
- package/src/bongos/auth.js +5 -1100
- package/src/module-api.js +3 -1
- package/tests/auth_admission_gate.mjs +3 -1
- package/tests/est_advisory.mjs +3 -1
- package/tests/goal_advisory.mjs +3 -2
- package/tests/goal_criterion_confirm_ui.mjs +6 -0
- package/tests/goal_subtitle.mjs +5 -2
- package/tests/goals_card_view.mjs +10 -3
- package/tests/grader_generated_provenance.mjs +3 -1
- package/tests/hall_palette.mjs +3 -1
- package/tests/helpers.mjs +58 -25
- package/tests/lib_sh_resolution.mjs +3 -1
- package/tests/membership_kind_lockstep.mjs +3 -1
- package/tests/migration_allocation.mjs +5 -2
- package/tests/patch_gate_ordering.mjs +3 -1
- package/tests/rank_tier_single_source.mjs +16 -3
- package/tests/reward_gate.mjs +3 -2
package/src/module-api.js
CHANGED
|
@@ -1091,8 +1091,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
1091
1091
|
// landed since 1.19.330 with no explicit bump. run 32791877167. (task 1002620)
|
|
1092
1092
|
// 1.19.332 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1093
1093
|
// landed since 1.19.331 with no explicit bump. run 32793033453. (task 1002620)
|
|
1094
|
+
// 1.19.333 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1095
|
+
// landed since 1.19.332 with no explicit bump. run 32793666555. (task 1002620)
|
|
1094
1096
|
// ---------------------------------------------------------------------------
|
|
1095
|
-
const CORE_VERSION = '1.19.
|
|
1097
|
+
const CORE_VERSION = '1.19.333'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
1096
1098
|
|
|
1097
1099
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
1098
1100
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { strict as assert } from 'node:assert';
|
|
14
14
|
import { createRequire } from 'node:module';
|
|
15
15
|
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { authSource } from './helpers.mjs';
|
|
16
17
|
|
|
17
18
|
const require = createRequire(import.meta.url);
|
|
18
19
|
const auth = require('../src/bongos/auth.js');
|
|
@@ -150,7 +151,8 @@ t('no login passed (legacy callers) behaves exactly as before — BLOCKED', () =
|
|
|
150
151
|
console.log('\nfirstTimeAdmissionBlocked — every call-site passes `login` (SR-19 non-drift, #1970):');
|
|
151
152
|
|
|
152
153
|
t('completeWebFlow + pollDeviceFlow both pass `login` to the gate', () => {
|
|
153
|
-
|
|
154
|
+
// task 1003206: the auth flows are auth.js + auth-*.js now — read the family.
|
|
155
|
+
const src = authSource();
|
|
154
156
|
const re = /firstTimeAdmissionBlocked\s*\(\s*\{[^}]*\}/g;
|
|
155
157
|
const callSites = [];
|
|
156
158
|
for (let m = re.exec(src); m; m = re.exec(src)) {
|
package/tests/est_advisory.mjs
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
import { strict as assert } from 'node:assert';
|
|
31
31
|
import fs from 'node:fs';
|
|
32
32
|
import { createRequire } from 'node:module';
|
|
33
|
+
import { taskRoutesSource } from './helpers.mjs';
|
|
33
34
|
|
|
34
35
|
const require = createRequire(import.meta.url);
|
|
35
36
|
const { adviseEstimate, pickRatio, buildEstAdvisory, MIN_MATERIAL_DELTA, SCALE_OK_RATIO } =
|
|
@@ -171,7 +172,8 @@ await t('the route attaches est_advisory to the 201 body, non-blocking', () => {
|
|
|
171
172
|
// literal because modules/lifecycle/routes/tasks.js is over the size ratchet's
|
|
172
173
|
// cap and main sits exactly AT the baseline — so this feature had to land at
|
|
173
174
|
// net-zero lines in that file. Asserting the shape keeps the fold honest.
|
|
174
|
-
|
|
175
|
+
// task 1003206: the task router is tasks.js + task-*.js now — read the family.
|
|
176
|
+
const src = taskRoutesSource();
|
|
175
177
|
const body201 = (src.match(/res\.status\(201\)\.json\(\{[\s\S]*?\}\);/) || [''])[0];
|
|
176
178
|
assert.ok(body201, 'found the 201 response body');
|
|
177
179
|
assert.match(body201, /est_advisory:/, 'est_advisory rides the create response');
|
package/tests/goal_advisory.mjs
CHANGED
|
@@ -17,14 +17,15 @@ import { strict as assert } from 'node:assert';
|
|
|
17
17
|
import { createRequire } from 'node:module';
|
|
18
18
|
import { readFileSync } from 'node:fs';
|
|
19
19
|
import http from 'node:http';
|
|
20
|
-
import { makeRunner, lifecycleDbSource } from './helpers.mjs';
|
|
20
|
+
import { makeRunner, lifecycleDbSource, taskRoutesSource } from './helpers.mjs';
|
|
21
21
|
|
|
22
22
|
process.env.NODE_ENV = 'test';
|
|
23
23
|
|
|
24
24
|
const require = createRequire(import.meta.url);
|
|
25
25
|
const { adviseGoal, candidateGoals, generalGoalTitle, buildGoalAdvisory } = require('../modules/lifecycle/goal-advisory.js');
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// task 1003206: the task router is tasks.js + task-*.js now — read the family.
|
|
28
|
+
const tasksSrc = taskRoutesSource();
|
|
28
29
|
// task 1003204: the lifecycle data layer is db.js + db-*.js now — read the family.
|
|
29
30
|
const dbSrc = lifecycleDbSource();
|
|
30
31
|
const { test, summary } = makeRunner();
|
|
@@ -40,6 +40,11 @@ const TASK_LIB_SRC = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/tas
|
|
|
40
40
|
// task 1003135: the page's pure presentational helpers moved to goals-lib.js
|
|
41
41
|
// (window.OTBGoalsLib) — run the REAL file too, same reasoning as task-lib above.
|
|
42
42
|
const GOALS_LIB_SRC = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/goals-lib.js'), 'utf8');
|
|
43
|
+
// task 1003206: the page's view painters moved to goals-render.js
|
|
44
|
+
// (window.OTBGoalsRender) — the second half of the same carve. Run the REAL file
|
|
45
|
+
// too, for the same reason: this is the only test that executes either board, so
|
|
46
|
+
// stubbing the renderers would let them rot unwatched.
|
|
47
|
+
const GOALS_RENDER_SRC = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/goals-render.js'), 'utf8');
|
|
43
48
|
|
|
44
49
|
const { test, summary } = makeRunner();
|
|
45
50
|
|
|
@@ -136,6 +141,7 @@ async function render({ rank = 'metic', goalStatus = 'open', criteria = Object.v
|
|
|
136
141
|
vm.createContext(sandbox);
|
|
137
142
|
vm.runInContext(TASK_LIB_SRC, sandbox, { filename: 'task-lib.js' });
|
|
138
143
|
vm.runInContext(GOALS_LIB_SRC, sandbox, { filename: 'goals-lib.js' });
|
|
144
|
+
vm.runInContext(GOALS_RENDER_SRC, sandbox, { filename: 'goals-render.js' });
|
|
139
145
|
vm.runInContext(SRC, sandbox, { filename: 'goals-page.js' });
|
|
140
146
|
|
|
141
147
|
// Let boot()'s promise chain settle (me → goals → details → route → render).
|
package/tests/goal_subtitle.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import { createRequire } from 'node:module';
|
|
|
18
18
|
import fs from 'node:fs';
|
|
19
19
|
import path from 'node:path';
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
|
+
import { goalsPageSource } from './helpers.mjs';
|
|
21
22
|
|
|
22
23
|
const require = createRequire(import.meta.url);
|
|
23
24
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -179,9 +180,11 @@ test('an unset subtitle is hidden; a set one is shown trimmed', () => {
|
|
|
179
180
|
});
|
|
180
181
|
|
|
181
182
|
test('on a LIST the subtitle is a tooltip, never a second visible line', () => {
|
|
182
|
-
|
|
183
|
+
// task 1003206: the row/card painters moved to goals-render.js — the second half
|
|
184
|
+
// of the carve goals-lib.js began — so read the family, not one filename.
|
|
185
|
+
const js = goalsPageSource();
|
|
183
186
|
// The helper lives in goals-lib.js — the file that exists because
|
|
184
|
-
// goals-page.js
|
|
187
|
+
// goals-page.js was over the excess-lines ratchet (task 1003135).
|
|
185
188
|
const lib = read('modules', 'hall-ui', 'public', 'goals-lib.js');
|
|
186
189
|
assert.match(lib, /function subtitleAttr/);
|
|
187
190
|
assert.match(lib, /escapeHtml\(t\)/, 'escaped, since it lands in an attribute');
|
|
@@ -12,10 +12,11 @@ import { strict as assert } from 'node:assert';
|
|
|
12
12
|
import fs from 'node:fs';
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
|
-
import { makeRunner } from './helpers.mjs';
|
|
15
|
+
import { makeRunner, goalsPageSource } from './helpers.mjs';
|
|
16
16
|
|
|
17
17
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
18
|
-
|
|
18
|
+
// task 1003206: the view painters moved to goals-render.js — read the family.
|
|
19
|
+
const SRC = goalsPageSource();
|
|
19
20
|
const CSS = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/goals.css'), 'utf8');
|
|
20
21
|
const { test, summary } = makeRunner();
|
|
21
22
|
|
|
@@ -28,7 +29,13 @@ await test('both views render from ONE fact source (goalRenderFacts) so they can
|
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
await test('renderList forks on the f-goal-view toggle AFTER grouping/filter/sort (both views share them)', () => {
|
|
31
|
-
|
|
32
|
+
// task 1003206: renderList moved to goals-render.js while the 'drag-to-reorder:
|
|
33
|
+
// RETIRED' marker that used to bound it stayed in goals-page.js, so slicing
|
|
34
|
+
// between the two now spans two files (or inverts). Bound the body by the next
|
|
35
|
+
// top-level function instead — that IS what 'renderList's body' means.
|
|
36
|
+
const start = SRC.indexOf('function renderList');
|
|
37
|
+
const nextFn = SRC.indexOf('\n function ', start + 1);
|
|
38
|
+
const body = SRC.slice(start, nextFn > start ? nextFn : undefined);
|
|
32
39
|
assert.match(body, /#f-goal-view/, 'the fork reads the toggle');
|
|
33
40
|
const sortIdx = body.indexOf('sortGoals(');
|
|
34
41
|
const forkIdx = body.indexOf('#f-goal-view');
|
|
@@ -36,6 +36,7 @@ import { createRequire } from 'node:module';
|
|
|
36
36
|
import fs from 'node:fs';
|
|
37
37
|
import path from 'node:path';
|
|
38
38
|
import { fileURLToPath } from 'node:url';
|
|
39
|
+
import { fitnessSource } from './helpers.mjs';
|
|
39
40
|
|
|
40
41
|
const require = createRequire(import.meta.url);
|
|
41
42
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -44,7 +45,8 @@ const prov = require(path.join(ROOT, 'modules/grading/generated-provenance.js'))
|
|
|
44
45
|
// ---- 1. lockstep with the fitness gate ----
|
|
45
46
|
|
|
46
47
|
test('the generator roster matches fitness.js checkGeneratedArtifactsFresh exactly', () => {
|
|
47
|
-
|
|
48
|
+
// task 1003206: the gate is fitness.js + fitness-*.js now — read the family.
|
|
49
|
+
const src = fitnessSource();
|
|
48
50
|
const fn = src.slice(src.indexOf('function checkGeneratedArtifactsFresh'));
|
|
49
51
|
const body = fn.slice(0, fn.indexOf('\nfunction ', 1));
|
|
50
52
|
|
package/tests/hall_palette.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import fs from 'node:fs';
|
|
|
18
18
|
import path from 'node:path';
|
|
19
19
|
import vm from 'node:vm';
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
|
+
import { hallSource } from './helpers.mjs';
|
|
21
22
|
|
|
22
23
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
23
24
|
const HALL = path.join(ROOT, 'modules/hall-ui/public');
|
|
@@ -90,7 +91,8 @@ function declaredHrefs(prefixTest) {
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
test('Standing section anchors exist in builders.js and are routable in shell.js', () => {
|
|
93
|
-
|
|
94
|
+
// task 1003206: STANDING_GROUPS moved to hall-render.js — read the family.
|
|
95
|
+
const groups = [...hallSource().matchAll(/\{ key: '([a-z]+)', label: '[^']+' \}/g)].map((m) => m[1]);
|
|
94
96
|
assert.ok(groups.length >= 4, `sanity: found STANDING_GROUPS (${groups})`);
|
|
95
97
|
const declared = declaredHrefs((h) => h.startsWith('/#standing-')).map((h) => h.replace('/#', ''));
|
|
96
98
|
assert.ok(declared.length, 'palette declares Standing sections');
|
package/tests/helpers.mjs
CHANGED
|
@@ -124,34 +124,67 @@ export function requireHostModule(require, spec, note) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
//
|
|
127
|
+
// ── carved-family source readers (tasks 1003204–1003206, goal 1000079) ────────
|
|
128
128
|
//
|
|
129
|
-
//
|
|
130
|
-
// db.js
|
|
131
|
-
// tests assert things about
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
129
|
+
// The de-monolith work split four big files into a facade plus siblings:
|
|
130
|
+
// modules/lifecycle/db.js, scripts/gds/ship.js, scripts/gds/fitness.js and
|
|
131
|
+
// modules/lifecycle/routes/tasks.js. A pile of tests assert things about one of
|
|
132
|
+
// those SUBJECTS by regexing its source — that every claim path gates on
|
|
133
|
+
// requires_rank, that a literal appears in exactly one place, that a gate
|
|
134
|
+
// precedes the first write. Those assertions were always about the subject, not
|
|
135
|
+
// about a filename, so they read the whole family.
|
|
136
|
+
//
|
|
137
|
+
// Reading the family (rather than repointing each test at whichever sibling
|
|
138
|
+
// happens to hold the code today) also means a future re-carve can move code
|
|
139
|
+
// between siblings without silently disarming the assertion.
|
|
140
|
+
function familySource(dir, matches) {
|
|
141
|
+
return fs.readdirSync(dir).filter(matches).sort()
|
|
142
|
+
.map((f) => fs.readFileSync(path.join(dir, f), 'utf8')).join('\n');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// The LIFECYCLE data layer: db.js (a re-export facade) + the twelve db-*.js units.
|
|
138
146
|
export function lifecycleDbSource(modulesDir = path.join(ROOT, 'modules')) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
.filter((f) => f === 'db.js' || (f.startsWith('db-') && f.endsWith('.js')))
|
|
142
|
-
.sort();
|
|
143
|
-
return files.map((f) => fs.readFileSync(path.join(dir, f), 'utf8')).join('\n');
|
|
147
|
+
return familySource(path.join(modulesDir, 'lifecycle'),
|
|
148
|
+
(f) => f === 'db.js' || (f.startsWith('db-') && f.endsWith('.js')));
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
// The companion to lifecycleDbSource above, for the same reason: task 1003205
|
|
149
|
-
// carved the 4,613-line scripts/gds/ship.js into ship.js (a re-export facade +
|
|
150
|
-
// the CLI entry point) plus ship-*.js phase modules. Tests that assert "the ship
|
|
151
|
-
// CLI does X" by regexing its source mean the CLI as a whole, not one file.
|
|
151
|
+
// The SHIP CLI: ship.js (facade + entry point) + the ship-*.js phase modules.
|
|
152
152
|
export function shipCliSource(scriptsDir = path.join(ROOT, 'scripts', 'gds')) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
return familySource(scriptsDir,
|
|
154
|
+
(f) => f === 'ship.js' || (f.startsWith('ship-') && f.endsWith('.js')));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// The architecture-fitness GATE: fitness.js (registry + runner), fitness-lib.js
|
|
158
|
+
// and the fitness-checks-*.js clusters. fitness-ratchets.js is deliberately in —
|
|
159
|
+
// it has always been a registered check module of the same gate.
|
|
160
|
+
export function fitnessSource(scriptsDir = path.join(ROOT, 'scripts', 'gds')) {
|
|
161
|
+
return familySource(scriptsDir,
|
|
162
|
+
(f) => f === 'fitness.js' || (f.startsWith('fitness-') && f.endsWith('.js')));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The BUILDERS' HALL page script: builders.js (state, data loading, wiring) plus
|
|
166
|
+
// hall-render.js, the view painters task 1003206 carved out of it.
|
|
167
|
+
export function hallSource(pubDir = path.join(ROOT, 'modules', 'hall-ui', 'public')) {
|
|
168
|
+
return familySource(pubDir, (f) => f === 'builders.js' || f === 'hall-render.js');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// The GOALS page script: goals-page.js plus its two carved siblings — goals-lib.js
|
|
172
|
+
// (pure helpers, task 1003135) and goals-render.js (view painters, task 1003206).
|
|
173
|
+
export function goalsPageSource(pubDir = path.join(ROOT, 'modules', 'hall-ui', 'public')) {
|
|
174
|
+
return familySource(pubDir, (f) => ['goals-page.js', 'goals-lib.js', 'goals-render.js'].includes(f));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// The KERNEL IDENTITY surface: auth.js (session resolution, the middleware and the
|
|
178
|
+
// page gates) plus the auth-*.js flow modules (config, admission, GitHub, IdP,
|
|
179
|
+
// Discord).
|
|
180
|
+
export function authSource(srcDir = path.join(ROOT, 'src', 'bongos')) {
|
|
181
|
+
return familySource(srcDir,
|
|
182
|
+
(f) => f === 'auth.js' || (f.startsWith('auth-') && f.endsWith('.js')));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// The TASK ROUTER: routes/tasks.js plus the task-*.js route modules it registers
|
|
186
|
+
// (task-write-routes.js holds POST /tasks and PATCH /tasks/:id).
|
|
187
|
+
export function taskRoutesSource(modulesDir = path.join(ROOT, 'modules')) {
|
|
188
|
+
return familySource(path.join(modulesDir, 'lifecycle', 'routes'),
|
|
189
|
+
(f) => f === 'tasks.js' || (f.startsWith('task-') && f.endsWith('.js')));
|
|
157
190
|
}
|
|
@@ -28,6 +28,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
28
28
|
import fs from 'node:fs';
|
|
29
29
|
import path from 'node:path';
|
|
30
30
|
import { fileURLToPath } from 'node:url';
|
|
31
|
+
import { fitnessSource } from './helpers.mjs';
|
|
31
32
|
|
|
32
33
|
const require = createRequire(import.meta.url);
|
|
33
34
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -122,7 +123,8 @@ test('gds_api_base falls back to the instance, never a foreign host', (t) => {
|
|
|
122
123
|
// ---- 3. the guard can now SEE a .sh re-hardcode ----------------------------
|
|
123
124
|
|
|
124
125
|
test('the host-identity fitness scan covers .sh', () => {
|
|
125
|
-
|
|
126
|
+
// task 1003206: the gate is fitness.js + fitness-*.js now — read the family.
|
|
127
|
+
const src = fitnessSource();
|
|
126
128
|
assert.match(src, /IDENTITY_SCAN_EXTS = new Set\(\[[^\]]*'\.sh'/,
|
|
127
129
|
'the scan extension set must include .sh, or no shell script is ever checked');
|
|
128
130
|
});
|
|
@@ -36,6 +36,7 @@ import { test } from 'node:test';
|
|
|
36
36
|
import fs from 'node:fs';
|
|
37
37
|
import path from 'node:path';
|
|
38
38
|
import { fileURLToPath } from 'node:url';
|
|
39
|
+
import { authSource } from './helpers.mjs';
|
|
39
40
|
|
|
40
41
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
41
42
|
const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
@@ -101,7 +102,8 @@ test('the value mapping is one shared function, not repeated inline', () => {
|
|
|
101
102
|
});
|
|
102
103
|
|
|
103
104
|
test('the sender writes BOTH spellings, computing the kind once (the cross-version window)', () => {
|
|
104
|
-
|
|
105
|
+
// task 1003206: the auth flows are auth.js + auth-*.js now — read the family.
|
|
106
|
+
const auth = authSource();
|
|
105
107
|
const body = auth.slice(auth.indexOf('async function reportMembershipCheckIn'), auth.indexOf('async function reportMembershipCheckIn') + 2400);
|
|
106
108
|
assert.match(body, /membership_kind: kind/, 'the new field goes on the wire');
|
|
107
109
|
assert.match(body, /role: kind === 'member' \? 'builder' : kind/,
|
|
@@ -28,7 +28,7 @@ import { readFileSync } from 'node:fs';
|
|
|
28
28
|
import { fileURLToPath } from 'node:url';
|
|
29
29
|
import { dirname, join } from 'node:path';
|
|
30
30
|
import { createRequire } from 'node:module';
|
|
31
|
-
import { lifecycleDbSource } from './helpers.mjs';
|
|
31
|
+
import { lifecycleDbSource, taskRoutesSource } from './helpers.mjs';
|
|
32
32
|
|
|
33
33
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
34
34
|
const repoRoot = join(__dirname, '..');
|
|
@@ -52,7 +52,8 @@ const migrationSql = read('migrations', '081_tasks_needs_migration.sql');
|
|
|
52
52
|
// the tasks db slice + the tasks route carved to modules/lifecycle/ at BV1.R86.
|
|
53
53
|
// task 1003204: the lifecycle data layer is db.js + db-*.js now — read the family.
|
|
54
54
|
const dbSrc = lifecycleDbSource();
|
|
55
|
-
|
|
55
|
+
// task 1003206: the task router is tasks.js + task-*.js now — read the family.
|
|
56
|
+
const routesSrc = taskRoutesSource();
|
|
56
57
|
const captureSrc = read('scripts', 'gds', 'capture.js');
|
|
57
58
|
|
|
58
59
|
// The allocator's trigger, reproduced as a pure predicate. This is the exact
|
|
@@ -148,6 +149,8 @@ function shouldReserveMigrationNumber(task) {
|
|
|
148
149
|
// "migration"/"schema" compounds, and a wrong verdict must be correctable
|
|
149
150
|
// via PATCH. Behavioral tests use the real exported detectsMigration.
|
|
150
151
|
const require = createRequire(import.meta.url);
|
|
152
|
+
// task 1003206: detectsMigration moved to task-route-helpers.js; tasks.js still
|
|
153
|
+
// re-exports it, so this keeps exercising the router's own public surface.
|
|
151
154
|
const { detectsMigration } = require('../modules/lifecycle/routes/tasks.js');
|
|
152
155
|
|
|
153
156
|
await test('classifier ignores code-migration and API-schema phrasing (task 1002648)', () => {
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
import assert from 'node:assert/strict';
|
|
19
19
|
import { test } from 'node:test';
|
|
20
20
|
import { readFileSync } from 'node:fs';
|
|
21
|
+
import { taskRoutesSource } from './helpers.mjs';
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
// task 1003206: PATCH /tasks/:id now lives in task-write-routes.js — read the family.
|
|
24
|
+
const src = taskRoutesSource();
|
|
23
25
|
|
|
24
26
|
// The PATCH handler slice: router.patch('/tasks/:id' … up to the next route.
|
|
25
27
|
function patchSlice(source) {
|
|
@@ -124,9 +124,18 @@ test('static ladder copies carry the exact canonical ladder', () => {
|
|
|
124
124
|
}
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
// task 1003206 carved the hall page scripts up; the rank tier maps travelled with
|
|
128
|
+
// the renderers that read them, so the pin and the allowlist follow the code.
|
|
129
|
+
const HALL_SCRIPTS = ['modules/hall-ui/public/builders.js', 'modules/hall-ui/public/goals-page.js',
|
|
130
|
+
'modules/hall-ui/public/hall-render.js', 'modules/hall-ui/public/goals-render.js'];
|
|
131
|
+
// Filtered INSIDE the test, not at module scope: extractRankMaps is declared
|
|
132
|
+
// further down, so calling it up here is a temporal-dead-zone crash.
|
|
133
|
+
const staticMapFiles = () => HALL_SCRIPTS.filter(
|
|
134
|
+
(rel) => extractRankMaps(fs.readFileSync(path.join(ROOT, rel), 'utf8')).length > 0);
|
|
128
135
|
test('hall static tier maps match the kernel map', () => {
|
|
129
|
-
|
|
136
|
+
const files = staticMapFiles();
|
|
137
|
+
assert.ok(files.length > 0, 'at least one hall script must carry the tier map');
|
|
138
|
+
for (const rel of files) {
|
|
130
139
|
const src = fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
131
140
|
const maps = extractRankMaps(src);
|
|
132
141
|
assert.ok(maps.length > 0, `${rel}: expected a rank tier map`);
|
|
@@ -146,7 +155,11 @@ const MAP_ALLOWLIST = new Set([
|
|
|
146
155
|
'scripts/gds/box-connect-lib.js',
|
|
147
156
|
'modules/dev-box/boxes.js',
|
|
148
157
|
'modules/hall-ui/public/builders.js',
|
|
149
|
-
|
|
158
|
+
// task 1003206 carved the hall page scripts up. builders.js KEPT its map (the
|
|
159
|
+
// renderers read it through the injected ctx), while goals-page.js's travelled
|
|
160
|
+
// into goals-render.js — so goals-page.js is pruned and hall-render.js is never
|
|
161
|
+
// added. The allowlist fails on a stale entry, which is the check working.
|
|
162
|
+
'modules/hall-ui/public/goals-render.js',
|
|
150
163
|
]);
|
|
151
164
|
// Where a rank-ladder array literal is allowed to exist.
|
|
152
165
|
const LADDER_ALLOWLIST = new Set([
|
package/tests/reward_gate.mjs
CHANGED
|
@@ -25,7 +25,7 @@ const db = require('../modules/lifecycle/db.js');
|
|
|
25
25
|
// the SAME singleton object db.js captured, so mutating its .query stubs the INSERT
|
|
26
26
|
// createTask runs — no database needed.
|
|
27
27
|
const sharedPool = require('../src/module-api.js').pool;
|
|
28
|
-
import { lifecycleDbSource } from './helpers.mjs';
|
|
28
|
+
import { lifecycleDbSource, taskRoutesSource } from './helpers.mjs';
|
|
29
29
|
|
|
30
30
|
const __dir = dirname(fileURLToPath(import.meta.url));
|
|
31
31
|
const root = join(__dir, '..');
|
|
@@ -132,7 +132,8 @@ t('null task is a no-op (no throw, no assignment)', () => {
|
|
|
132
132
|
// ---------------------------------------------------------------------------
|
|
133
133
|
console.log('\nenforcement points (source-wiring — AUTO-ASSIGN):');
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
// task 1003206: POST /tasks now lives in task-write-routes.js — read the family.
|
|
136
|
+
const tasksRouteSrc = taskRoutesSource();
|
|
136
137
|
// task 1003204: the lifecycle data layer is db.js + db-*.js now — read the family.
|
|
137
138
|
const dbSrc = lifecycleDbSource();
|
|
138
139
|
const migration178 = readFileSync(join(root, 'migrations/178_reward_gate_auto_assign_revert_autopromote.sql'), 'utf8');
|