@bongos/core 1.19.250 → 1.19.251
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 +69 -14
- package/docs/copy-inventory.md +1430 -0
- package/docs/copy-registry.json +13293 -0
- package/modules/copy-desk/CLAUDE.md +15 -0
- package/modules/copy-desk/flags.js +245 -0
- package/modules/copy-desk/migrations/copy_desk_001_flags.sql +128 -0
- package/modules/copy-desk/module.json +11 -0
- package/modules/copy-desk/registry.js +317 -0
- package/modules/copy-desk/routes/copy-desk.js +272 -0
- package/modules/copy-desk/tests/copy_flags.mjs +246 -0
- package/modules/copy-desk/tests/copy_no_cms.mjs +104 -0
- package/modules/copy-desk/tests/copy_queue.mjs +257 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/publish-manifest.js +9 -0
- package/src/module-api.js +3 -1
- package/tests/publish_manifest.mjs +82 -0
package/src/module-api.js
CHANGED
|
@@ -927,8 +927,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
927
927
|
// landed since 1.19.248 with no explicit bump. run 32199293372. (task 1002620)
|
|
928
928
|
// 1.19.250 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
929
929
|
// landed since 1.19.249 with no explicit bump. run 32203357427. (task 1002620)
|
|
930
|
+
// 1.19.251 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
931
|
+
// landed since 1.19.250 with no explicit bump. run 32204008770. (task 1002620)
|
|
930
932
|
// ---------------------------------------------------------------------------
|
|
931
|
-
const CORE_VERSION = '1.19.
|
|
933
|
+
const CORE_VERSION = '1.19.251'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
932
934
|
|
|
933
935
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
934
936
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -15,7 +15,15 @@
|
|
|
15
15
|
|
|
16
16
|
import { strict as assert } from 'node:assert';
|
|
17
17
|
import { createRequire } from 'node:module';
|
|
18
|
+
// fs/path/ROOT serve the disk-DERIVED guards at the bottom of this file (task
|
|
19
|
+
// 1003132). They must read the tree rather than a list: an enumerated assertion
|
|
20
|
+
// would miss the next unclassified module exactly as the enumerated allowlist
|
|
21
|
+
// missed the one that prompted them.
|
|
22
|
+
import fs from 'node:fs';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import url from 'node:url';
|
|
18
25
|
|
|
26
|
+
const ROOT = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '..');
|
|
19
27
|
const require = createRequire(import.meta.url);
|
|
20
28
|
const m = require('../scripts/gds/publish-manifest.js');
|
|
21
29
|
const {
|
|
@@ -179,6 +187,80 @@ t('every PROTECTED_GLOB is either topology-excluded or publishable (the methodol
|
|
|
179
187
|
assert.ok(isPublishable(g), `protected surface "${g}" is neither denied nor publishable — re-decide the carve-out`);
|
|
180
188
|
}
|
|
181
189
|
});
|
|
190
|
+
// ── the publish question, asked of the tree itself (task 1003132) ───────────────────
|
|
191
|
+
//
|
|
192
|
+
// THE GAP THESE CLOSE. modules/copy-desk/ was designed, built, tested against a real
|
|
193
|
+
// Postgres, graded, merged and very nearly RELEASED while publishing nothing. Not one
|
|
194
|
+
// of the 429 unit tests, 20+ fitness checks, or the adversarial grader asks the publish
|
|
195
|
+
// question, and the assertions above enumerate representative paths — so a brand-new
|
|
196
|
+
// module key appears in no list and is simply invisible.
|
|
197
|
+
//
|
|
198
|
+
// The failure is worse than "the feature does not ship", because it is ASYMMETRIC: the
|
|
199
|
+
// module's hall page ships anyway (modules/hall-ui/ is one allowlisted subtree), so a
|
|
200
|
+
// release delivers a nav tab and a page whose every API call 404s.
|
|
201
|
+
//
|
|
202
|
+
// Both guards DERIVE from disk. A list here would rot the same way the allowlist did.
|
|
203
|
+
//
|
|
204
|
+
// Modules deliberately not published, on the record. An entry here is a decision
|
|
205
|
+
// someone made, not a gap someone forgot — and every entry needs the task or idea that
|
|
206
|
+
// records the decision, so this can never become a quiet parking lot.
|
|
207
|
+
const KNOWN_UNPUBLISHED_MODULES = new Map([
|
|
208
|
+
// Same gap as copy-desk, found by the guard below the moment it was written. LATENT
|
|
209
|
+
// rather than live only because agents is default:false — the day a released instance
|
|
210
|
+
// enables it, the loader MODULE_NOT_FOUNDs, which is exactly what the provisioning
|
|
211
|
+
// (task 2135) and platform-identity (task 1002235) allowlist entries exist to prevent.
|
|
212
|
+
// Left for goal 1000038 rather than fixed here: deciding what the published core
|
|
213
|
+
// contains for the agents module is that goal's call, not a drive-by from a copy-desk
|
|
214
|
+
// task. Filed as idea 1000797 with the one-line fix.
|
|
215
|
+
['agents', 'idea 1000797'],
|
|
216
|
+
]);
|
|
217
|
+
|
|
218
|
+
t('every module on disk is either publishable or deliberately unpublished (a new module cannot be silently invisible)', () => {
|
|
219
|
+
const modulesDir = path.join(ROOT, 'modules');
|
|
220
|
+
const keys = fs.readdirSync(modulesDir, { withFileTypes: true })
|
|
221
|
+
.filter((d) => d.isDirectory() && fs.existsSync(path.join(modulesDir, d.name, 'module.json')))
|
|
222
|
+
.map((d) => d.name);
|
|
223
|
+
assert.ok(keys.length > 5, `sanity: only ${keys.length} modules found on disk — the scan is broken, not the tree`);
|
|
224
|
+
|
|
225
|
+
const unclassified = keys.filter((k) => {
|
|
226
|
+
const manifest = `modules/${k}/module.json`;
|
|
227
|
+
return !isPublishable(manifest) && !matchesDeny(manifest) && !KNOWN_UNPUBLISHED_MODULES.has(k);
|
|
228
|
+
});
|
|
229
|
+
assert.deepEqual(unclassified, [],
|
|
230
|
+
'these modules are in neither the allowlist nor a deny list, so they publish NOTHING. Add each to PUBLISH_ALLOWLIST, deny it on the record, or register it in KNOWN_UNPUBLISHED_MODULES with the task that decided it.');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
t('every KNOWN_UNPUBLISHED_MODULES entry names a real module and a real decision', () => {
|
|
234
|
+
// Two ways this exception list rots: an entry outlives the module (and silently
|
|
235
|
+
// exempts nothing), or an entry outlives the fix (and silently exempts something
|
|
236
|
+
// already fixed). Both make the guard above weaker than it looks.
|
|
237
|
+
for (const [key, ref] of KNOWN_UNPUBLISHED_MODULES) {
|
|
238
|
+
assert.ok(fs.existsSync(path.join(ROOT, 'modules', key, 'module.json')),
|
|
239
|
+
`KNOWN_UNPUBLISHED_MODULES names "${key}", which is not a module on disk — drop the entry`);
|
|
240
|
+
assert.ok(/\b(task|idea)\s+\d+/.test(ref),
|
|
241
|
+
`KNOWN_UNPUBLISHED_MODULES["${key}"] must cite the task or idea that decided it, got "${ref}"`);
|
|
242
|
+
assert.equal(isPublishable(`modules/${key}/module.json`), false,
|
|
243
|
+
`"${key}" is now publishable — delete its KNOWN_UNPUBLISHED_MODULES entry so the guard covers it again`);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
t('a hall page named for a module ships only if that module ships (never a tab whose API 404s)', () => {
|
|
248
|
+
const hallDir = path.join(ROOT, 'modules/hall-ui/public');
|
|
249
|
+
const modulesDir = path.join(ROOT, 'modules');
|
|
250
|
+
if (!fs.existsSync(hallDir)) return;
|
|
251
|
+
const orphans = [];
|
|
252
|
+
for (const f of fs.readdirSync(hallDir)) {
|
|
253
|
+
if (!f.endsWith('.html')) continue;
|
|
254
|
+
const key = f.replace(/\.html$/, '');
|
|
255
|
+
// Only pages that NAME a module are paired — the hall's own pages (work, goals,
|
|
256
|
+
// settings…) have no module and are not the subject of this rule.
|
|
257
|
+
if (!fs.existsSync(path.join(modulesDir, key, 'module.json'))) continue;
|
|
258
|
+
if (!isPublishable(`modules/${key}/module.json`)) orphans.push(f);
|
|
259
|
+
}
|
|
260
|
+
assert.deepEqual(orphans, [],
|
|
261
|
+
'these hall pages would ship to instances whose backing module does not — a nav tab and a page whose every call 404s. Publish the module, or stop publishing the page.');
|
|
262
|
+
});
|
|
263
|
+
|
|
182
264
|
t('the topology subset of the protected surfaces is never publishable', () => {
|
|
183
265
|
for (const g of PROTECTED_TOPOLOGY_EXCLUDE) {
|
|
184
266
|
assert.equal(isPublishable(g), false, `topology surface "${g}" must not publish`);
|