@bongos/core 1.19.385 → 1.19.386

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.385",
6
- "core_contract": "1.19.385",
7
- "source_commit": "3ed24b93e1f32dddb11c2a7a8bfaa9dda77a6f31",
5
+ "core_version": "1.19.386",
6
+ "core_contract": "1.19.386",
7
+ "source_commit": "c4899bbdaafe758d4521d6cb7944ad0117886573",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-27T21:33:52.536Z",
9
+ "built_at": "2026-08-27T21:58:01.005Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 338,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 1963,
20
- "tree_sha256": "405834d1bb0740aa2af5d7666798ac5219e895d514d397afb2c9c53953a431c8",
20
+ "tree_sha256": "856370a346d104a96b56e2fe9a3fefd50a50298a18e82c9afa13ef04387f6b7a",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -5117,12 +5117,12 @@
5117
5117
  {
5118
5118
  "path": "package-lock.json",
5119
5119
  "mode": "0000644",
5120
- "sha256": "44a05f902a0d9063f2642c03a377c0c850dc4871e65c8b680c1190ca905bb3ec"
5120
+ "sha256": "34407c6061bf61f8ec416b91f30da5ae1140c1e584e6721af64fbadadb60c9b0"
5121
5121
  },
5122
5122
  {
5123
5123
  "path": "package.json",
5124
5124
  "mode": "0000644",
5125
- "sha256": "da469f97be509ad2739415aa339e06765bb4b3ea0c828620fb72391e76bb8862"
5125
+ "sha256": "e49313249eef5acc6d3a2926aeb5725f0773d8d4300393a8ed57a3016a25a995"
5126
5126
  },
5127
5127
  {
5128
5128
  "path": "public-docs/index.html",
@@ -5782,7 +5782,7 @@
5782
5782
  {
5783
5783
  "path": "scripts/gds/docs-entropy.js",
5784
5784
  "mode": "0000644",
5785
- "sha256": "1a7cbe47158e4de63c1b788d6bb4f682584723a45c1824ab2ae3fbf92a54fbce"
5785
+ "sha256": "e052ddf4d44c0d67512cb14e150cd309a9ab09414c557db8319a57fd8f0d6961"
5786
5786
  },
5787
5787
  {
5788
5788
  "path": "scripts/gds/doctor.js",
@@ -7032,7 +7032,7 @@
7032
7032
  {
7033
7033
  "path": "src/module-api.js",
7034
7034
  "mode": "0000644",
7035
- "sha256": "63478a33b8d134113541ea814481eedb00ad89ac0b6777e87a1a6053b5718d72"
7035
+ "sha256": "28a5f25668bc0297f421e200dbb658a5365db71874af4f8fd29c37016b4dcd29"
7036
7036
  },
7037
7037
  {
7038
7038
  "path": "src/module-loader/catalog.js",
@@ -7862,7 +7862,7 @@
7862
7862
  {
7863
7863
  "path": "tests/docs_entropy.mjs",
7864
7864
  "mode": "0000644",
7865
- "sha256": "4d64164d45d6b81d706074b8394da4f3d0f7f8c5263a37a287a163d6a746a96b"
7865
+ "sha256": "c3ef388bb7baacd4da4319fed82ceb5687e0d444cacce2ee84f9061dccbd1018"
7866
7866
  },
7867
7867
  {
7868
7868
  "path": "tests/docs_openapi_route.mjs",
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.385",
3
+ "version": "1.19.386",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.385",
9
+ "version": "1.19.386",
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.385",
3
+ "version": "1.19.386",
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",
@@ -89,7 +89,17 @@ function parseFile(absPath) {
89
89
  return { headings: [], links: [], paragraphs: [] };
90
90
  }
91
91
 
92
- const lines = raw.split('\n');
92
+ // Split on CRLF **or** LF, and drop a leading BOM (task 1003314). A Windows
93
+ // checkout gets CRLF from git, and splitting on a bare newline then leaves a
94
+ // trailing carriage return on every line — which the heading regex below
95
+ // cannot match, because `.` excludes line terminators and `$` is not in
96
+ // multiline mode. The file parsed as having ZERO headings, so every
97
+ // [text](file.md#anchor) pointing into it was reported as a broken anchor:
98
+ // doc_broken_anchors read 21 on Windows and 6 in CI, and the quality ratchet
99
+ // a Windows builder ran was pure noise. Same failure family as task 1002526's
100
+ // `git ls-files` quoting bug, one layer in — a gate that reports confidently
101
+ // and wrongly on one platform.
102
+ const lines = raw.replace(/^\uFEFF/, '').split(/\r?\n/);
93
103
  const headings = [];
94
104
  const links = [];
95
105
  const paragraphs = [];
package/src/module-api.js CHANGED
@@ -1210,8 +1210,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
1210
1210
  // landed since 1.19.383 with no explicit bump. run 33116184189. (task 1002620)
1211
1211
  // 1.19.385 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1212
1212
  // landed since 1.19.384 with no explicit bump. run 33118682829. (task 1002620)
1213
+ // 1.19.386 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1214
+ // landed since 1.19.385 with no explicit bump. run 33120468176. (task 1002620)
1213
1215
  // ---------------------------------------------------------------------------
1214
- const CORE_VERSION = '1.19.385'; // CI auto-patch carrier (ADR 0161); see changelog above
1216
+ const CORE_VERSION = '1.19.386'; // CI auto-patch carrier (ADR 0161); see changelog above
1215
1217
 
1216
1218
  // A namespaced logger so a module's log lines are attributable + consistent.
1217
1219
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -12,12 +12,14 @@ import { test } from 'node:test';
12
12
  import { execFileSync } from 'node:child_process';
13
13
  import { createRequire } from 'node:module';
14
14
  import { fileURLToPath } from 'node:url';
15
+ import fs from 'node:fs';
16
+ import os from 'node:os';
15
17
  import path from 'node:path';
16
18
 
17
19
  const require = createRequire(import.meta.url);
18
20
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
19
21
  const SCANNER = path.join(ROOT, 'scripts', 'gds', 'docs-entropy.js');
20
- const { collectMarkdownFiles } = require(SCANNER); // require.main-guarded → no scan on import
22
+ const { collectMarkdownFiles, parseFile } = require(SCANNER); // require.main-guarded → no scan on import
21
23
 
22
24
  test('collectMarkdownFiles passes the glob as an argv array, never a shell string', () => {
23
25
  let seen = null;
@@ -53,3 +55,86 @@ test('the real scan enumerates the repo (the regression: it reported on 0 files)
53
55
  assert.ok(Number.isFinite(result.stale_links));
54
56
  assert.ok(Number.isFinite(result.broken_anchors));
55
57
  });
58
+
59
+ // --- CRLF: a Windows checkout must parse exactly like a Linux one (task 1003314) ---
60
+ //
61
+ // The bug: parseFile() split on a bare '\n', so on a Windows checkout (git hands
62
+ // out CRLF) every line kept a trailing '\r'. The heading regex /^(#{1,6})\s+(.+)$/
63
+ // cannot match that — '.' excludes line terminators and '$' is not in multiline
64
+ // mode — so EVERY CRLF file parsed as having zero headings, and every
65
+ // [text](file.md#anchor) pointing into one was reported broken. doc_broken_anchors
66
+ // read 21 on Windows against a baseline of 6, which made the quality ratchet
67
+ // unusable there: a builder could not tell a real regression from platform noise.
68
+ // Same family as the `git ls-files` quoting bug above — a gate that reports
69
+ // confidently and WRONGLY on one platform only.
70
+
71
+ const DOC_LINES = [
72
+ '# Title one',
73
+ '',
74
+ 'Some prose with a [link](other.md#deep-anchor) in it.',
75
+ '',
76
+ '## 12. Session Update Protocol',
77
+ '',
78
+ 'More prose.',
79
+ ];
80
+
81
+ // Write `text` to a temp .md and parse it — parseFile takes a path, not a string.
82
+ function parseString(text) {
83
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'docs-entropy-eol-'));
84
+ try {
85
+ const file = path.join(dir, 'sample.md');
86
+ fs.writeFileSync(file, text);
87
+ return parseFile(file);
88
+ } finally {
89
+ fs.rmSync(dir, { recursive: true, force: true });
90
+ }
91
+ }
92
+
93
+ test('parseFile reads CRLF and LF identically — headings, slugs and links', () => {
94
+ const lf = parseString(DOC_LINES.join('\n'));
95
+ const crlf = parseString(DOC_LINES.join('\r\n'));
96
+
97
+ assert.equal(lf.headings.length, 2, 'fixture sanity: the LF form has two headings');
98
+ assert.deepEqual(
99
+ crlf.headings, lf.headings,
100
+ 'a CRLF file must parse to the same headings as the LF one — before this fix it parsed to NONE',
101
+ );
102
+ assert.deepEqual(crlf.links.map((l) => l.href), lf.links.map((l) => l.href));
103
+ });
104
+
105
+ test('parseFile slugs a CRLF heading without a trailing carriage return', () => {
106
+ const slugs = parseString(DOC_LINES.join('\r\n')).headings.map((h) => h.slug);
107
+ assert.deepEqual(
108
+ slugs, ['title-one', '12-session-update-protocol'],
109
+ 'the real anchor CLAUDE.md cites — a stray \\r in the slug is what made it report as "missing"',
110
+ );
111
+ assert.ok(!slugs.some((s) => s.includes('\r')), 'no slug carries a carriage return');
112
+ });
113
+
114
+ test('parseFile ignores a leading BOM, so a BOM file is not one heading short', () => {
115
+ // Same class, different byte: PowerShell writes UTF-8 WITH BOM by default
116
+ // (scripts/gds/CLAUDE.md warns about this for JSON bodies) and
117
+ // readFileSync('utf8') does not strip it — the BOM would sit before the first
118
+ // '#' and hide that heading.
119
+ const withBom = parseString('' + DOC_LINES.join('\r\n'));
120
+ assert.equal(withBom.headings.length, 2, 'the first heading survives a BOM');
121
+ assert.equal(withBom.headings[0].text, 'Title one');
122
+ });
123
+
124
+ test('the real scan on THIS checkout matches the CI baselines (the platform-parity proof)', () => {
125
+ // The point of the fix: the number a Windows builder sees is the number CI
126
+ // sees. Read the baseline rather than hardcoding it, so this stays honest as
127
+ // the ratchet legitimately tightens.
128
+ const stdout = execFileSync(process.execPath, [SCANNER, '--json'], {
129
+ cwd: ROOT, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024,
130
+ });
131
+ const result = JSON.parse(stdout);
132
+ const baselines = JSON.parse(
133
+ fs.readFileSync(path.join(ROOT, 'config', 'fitness-baselines.json'), 'utf8'),
134
+ ).metrics;
135
+ assert.ok(
136
+ result.broken_anchors <= baselines.doc_broken_anchors,
137
+ `broken_anchors ${result.broken_anchors} exceeds the baseline ${baselines.doc_broken_anchors} — `
138
+ + 'on a CRLF checkout this read 21, because every heading in every CRLF file went unparsed',
139
+ );
140
+ });