@bongos/core 1.19.201 → 1.19.202

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,11 +2,11 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.201",
6
- "core_contract": "1.19.201",
7
- "source_commit": "d12ce65286155db1a4609b647f8b5c6f3b7702c8",
5
+ "core_version": "1.19.202",
6
+ "core_contract": "1.19.202",
7
+ "source_commit": "241b029c800ce3bdb38f7d581e44d95d27656007",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-17T19:08:54.639Z",
9
+ "built_at": "2026-08-17T19:15:32.076Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 310,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 1625,
20
- "tree_sha256": "300276855875716739e395ee304fab665d8e9cc9ee33839e0544ce763fea9a17",
20
+ "tree_sha256": "d0af1afec31904ff2d8c0ba6a68c5960c6b333ef65c66938843f2a7bd681f4f0",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -4072,7 +4072,7 @@
4072
4072
  {
4073
4073
  "path": "modules/security/artifact-scan/floor.js",
4074
4074
  "mode": "0000644",
4075
- "sha256": "c3daa70d6a07cb64040f0f0c88b359ef7ff284c66b0282297253d726b25ba93b"
4075
+ "sha256": "27421162e08ed14ba9e26be02e11c936c566ad113b76a90d452474d7e867093b"
4076
4076
  },
4077
4077
  {
4078
4078
  "path": "modules/security/artifact-scan/limits.js",
@@ -4157,7 +4157,7 @@
4157
4157
  {
4158
4158
  "path": "modules/security/tests/floor.mjs",
4159
4159
  "mode": "0000644",
4160
- "sha256": "799dca44c7570ef11de2df5b721428de2670343882b6942eb6bac62c1b3b40ca"
4160
+ "sha256": "7eaed4b59cce956509ca7ebcb92207d362f191ec9b54be90d3c47d069b8149e7"
4161
4161
  },
4162
4162
  {
4163
4163
  "path": "modules/security/tests/mirror.mjs",
@@ -4272,12 +4272,12 @@
4272
4272
  {
4273
4273
  "path": "package-lock.json",
4274
4274
  "mode": "0000644",
4275
- "sha256": "4cade958ecb05d2f70af056f7316e5e773771f304236d17ceeddc04b1147899b"
4275
+ "sha256": "28f5946694aefef1201397cdb8962d38b2b1d5d0904ef6f76b5b1591f0f6a2e8"
4276
4276
  },
4277
4277
  {
4278
4278
  "path": "package.json",
4279
4279
  "mode": "0000644",
4280
- "sha256": "7da6bdc2ce6176f9c673bee2f697426ee7a94cc151823d65526c9fe50e646746"
4280
+ "sha256": "cbf3b235c2ed444a8bf84a0719df6fbe81f8ad98dcbbf5eaf3740338af1e53a3"
4281
4281
  },
4282
4282
  {
4283
4283
  "path": "public-docs/index.html",
@@ -5887,7 +5887,7 @@
5887
5887
  {
5888
5888
  "path": "src/module-api.js",
5889
5889
  "mode": "0000644",
5890
- "sha256": "ed3ac8884e7e1deaa6ddd27accdc066707203de95a45924c1255b6b28e45527d"
5890
+ "sha256": "2cd85c33fc8008eec96025eeaaa528590157902642653819bf20b580e1d031a5"
5891
5891
  },
5892
5892
  {
5893
5893
  "path": "src/module-loader/catalog.js",
@@ -191,6 +191,54 @@ function coverageFindings(corpus) {
191
191
  return findings;
192
192
  }
193
193
 
194
+ // Cap the merged-path list so an artifact vendoring thousands of identical
195
+ // copies cannot balloon the persisted report through its own duplication.
196
+ const MAX_DUPLICATE_PATHS = 20;
197
+
198
+ // A repo that vendors the same tree N times produces N identical findings from
199
+ // one underlying file (same detector, same evidence, byte-identical content) —
200
+ // which triples counts and buries the real signal. Collapse findings that agree
201
+ // on (code, severity, message) AND whose files are byte-identical per the
202
+ // manifest sha256; the survivor lists the other copies. Keyed on the full
203
+ // message so per-path evidence (differing line numbers, labels) never merges
204
+ // wrongly, and findings without a manifest file entry ('(floor)', '(fetch)',
205
+ // directories, symlinks) pass through untouched. Verdict arithmetic is
206
+ // unaffected: max() over findings is idempotent under duplication.
207
+ function dedupeFindings(findings, entries) {
208
+ const shaByPath = new Map();
209
+ for (const e of entries || []) {
210
+ if (e && e.kind === 'file' && e.sha256) shaByPath.set(scrubUntrusted(String(e.path)), e.sha256);
211
+ }
212
+ const groups = new Map();
213
+ const slots = [];
214
+ for (const f of findings) {
215
+ const sha = f && typeof f.file === 'string' ? shaByPath.get(f.file) : null;
216
+ if (!sha) { slots.push({ finding: f }); continue; }
217
+ const key = JSON.stringify([f.code, f.severity, f.message, sha]);
218
+ const group = groups.get(key);
219
+ if (!group) {
220
+ groups.set(key, { first: f, dups: [] });
221
+ slots.push({ key });
222
+ } else {
223
+ group.dups.push(f.file);
224
+ }
225
+ }
226
+ return slots.map((slot) => {
227
+ if (slot.finding) return slot.finding;
228
+ const { first, dups } = groups.get(slot.key);
229
+ if (dups.length === 0) return first;
230
+ const baseDetail = first.detail && typeof first.detail === 'object' && !Array.isArray(first.detail) ? first.detail : {};
231
+ return {
232
+ ...first,
233
+ detail: {
234
+ ...baseDetail,
235
+ duplicate_files: dups.slice(0, MAX_DUPLICATE_PATHS),
236
+ duplicate_count: dups.length,
237
+ },
238
+ };
239
+ });
240
+ }
241
+
194
242
  // Run every detector crash-isolated: a detector that throws yields a finding,
195
243
  // never a hole in the report. `detectors` is injectable so the crash-isolation
196
244
  // contract is unit-testable with a deliberately-throwing detector.
@@ -273,15 +321,20 @@ async function runFloor({ pristineDir, quarantineRoot, entries, sha = null, cont
273
321
  'The floor could not read the artifact tree at all — nothing here was reviewed.', { error: corpusError }));
274
322
  }
275
323
 
324
+ // Collapse vendored-copy duplicates LAST, so every producing step above is
325
+ // covered; crash-isolated with the raw list as fallback (a broken dedupe must
326
+ // degrade to duplicate noise, never to lost findings).
327
+ const finalFindings = isolate('dedupe', () => dedupeFindings(findings, entries)) || findings;
328
+
276
329
  const report = {
277
330
  floor_version: FLOOR_VERSION,
278
331
  detectors_run: DETECTORS.map(([name]) => name),
279
332
  detector_errors: errors,
280
333
  generated_at: new Date().toISOString(),
281
334
  target: { sha, content_hash: contentHash },
282
- findings,
283
- counts: countBySeverity(findings),
284
- floor_verdict: computeFloorVerdict(findings),
335
+ findings: finalFindings,
336
+ counts: countBySeverity(finalFindings),
337
+ floor_verdict: computeFloorVerdict(finalFindings),
285
338
  // Printed, never scored — the reader's power budget for the artifact.
286
339
  capabilities: capabilityInventory,
287
340
  coverage: {
@@ -314,6 +367,7 @@ module.exports = {
314
367
  countBySeverity,
315
368
  coOccurrence,
316
369
  coverageFindings,
370
+ dedupeFindings,
317
371
  runDetectors,
318
372
  runFloor,
319
373
  };
@@ -58,6 +58,43 @@ function corpusOf(fileMap) {
58
58
  const codesOf = (findings) => findings.map((f) => f.code);
59
59
  const hasCode = (findings, code) => findings.some((f) => f.code === code);
60
60
 
61
+ // ---------- dedupe across byte-identical files ----------
62
+
63
+ await test('dedupe: identical findings on byte-identical files collapse to one, listing the copies', () => {
64
+ const entries = [
65
+ { path: 'a/data.csv', kind: 'file', size: 10, sha256: 'aaa' },
66
+ { path: 'b/data.csv', kind: 'file', size: 10, sha256: 'aaa' },
67
+ { path: 'c/data.csv', kind: 'file', size: 10, sha256: 'aaa' },
68
+ { path: 'd/other.csv', kind: 'file', size: 10, sha256: 'bbb' },
69
+ ];
70
+ const mk = (file) => ({ code: 'x_hit', severity: 'critical', file, message: 'same claim', detail: { k: 1 } });
71
+ const input = [mk('a/data.csv'), mk('b/data.csv'), mk('c/data.csv'), mk('d/other.csv'),
72
+ { code: 'detector_error', severity: 'high', file: '(floor)', message: 'crashed', detail: null }];
73
+ const out = floor.dedupeFindings(input, entries);
74
+ // vendored copies collapse; different bytes (d/) and non-file findings survive
75
+ assert.equal(out.length, 3);
76
+ const merged = out.find((f) => f.file === 'a/data.csv');
77
+ assert.deepEqual(merged.detail.duplicate_files, ['b/data.csv', 'c/data.csv']);
78
+ assert.equal(merged.detail.duplicate_count, 2);
79
+ assert.equal(merged.detail.k, 1, 'original detail keys survive the merge');
80
+ assert.ok(out.some((f) => f.file === 'd/other.csv'));
81
+ assert.ok(out.some((f) => f.file === '(floor)'));
82
+ // input findings were not mutated (the merged copy is a new object)
83
+ assert.equal(input[0].detail.duplicate_count, undefined);
84
+ });
85
+
86
+ await test('dedupe: same file bytes but different messages stay separate findings', () => {
87
+ const entries = [
88
+ { path: 'a.js', kind: 'file', size: 5, sha256: 'ccc' },
89
+ { path: 'b.js', kind: 'file', size: 5, sha256: 'ccc' },
90
+ ];
91
+ const out = floor.dedupeFindings([
92
+ { code: 'y', severity: 'medium', file: 'a.js', message: 'claim at line 3', detail: null },
93
+ { code: 'y', severity: 'medium', file: 'b.js', message: 'claim at line 9', detail: null },
94
+ ], entries);
95
+ assert.equal(out.length, 2);
96
+ });
97
+
61
98
  // ---------- npm lifecycle ----------
62
99
 
63
100
  await test('npm-lifecycle: quotes a postinstall verbatim as a high finding', () => {
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.201",
3
+ "version": "1.19.202",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.201",
9
+ "version": "1.19.202",
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.201",
3
+ "version": "1.19.202",
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/src/module-api.js CHANGED
@@ -829,8 +829,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
829
829
  // landed since 1.19.199 with no explicit bump. run 32058296632. (task 1002620)
830
830
  // 1.19.201 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
831
831
  // landed since 1.19.200 with no explicit bump. run 32058666256. (task 1002620)
832
+ // 1.19.202 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
833
+ // landed since 1.19.201 with no explicit bump. run 32059276345. (task 1002620)
832
834
  // ---------------------------------------------------------------------------
833
- const CORE_VERSION = '1.19.201'; // CI auto-patch carrier (ADR 0161); see changelog above
835
+ const CORE_VERSION = '1.19.202'; // CI auto-patch carrier (ADR 0161); see changelog above
834
836
 
835
837
  // A namespaced logger so a module's log lines are attributable + consistent.
836
838
  // Usage: const log = api.logger('dev-box'); log.info('mounted');