@bongos/core 1.19.850 → 1.19.851

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.850",
6
- "core_contract": "1.19.850",
7
- "source_commit": "232e375d3248cfc923d287f61d29cb6c5f59c5d9",
5
+ "core_version": "1.19.851",
6
+ "core_contract": "1.19.851",
7
+ "source_commit": "da155ea160e5cc9856e3f5cf748f295b8249fda3",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-17T20:32:54.381Z",
9
+ "built_at": "2026-09-17T20:50:42.971Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 496,
13
13
  "agent_docs_stubbed": 26,
14
- "functional_verbatim": 2276,
14
+ "functional_verbatim": 2277,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2798,
20
- "tree_sha256": "12391d158894c3d0cb4e4073c3939f9c3e83705fa0406663fe5a30859fba4af4",
19
+ "file_count": 2799,
20
+ "tree_sha256": "7da0b3dfc799f5f86bd7a462eab350162e41438285181ab7698d19e15c38cc7a",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -302,7 +302,7 @@
302
302
  {
303
303
  "path": ".gitattributes",
304
304
  "mode": "0000644",
305
- "sha256": "2d993829478b5f8931e5a8248818b70279055d1af643e51f07de6161eab593aa"
305
+ "sha256": "dace360d1e995ce2a7401a275a7ed68f6ebb877da948f7cf5ff710a9ce8c8bfc"
306
306
  },
307
307
  {
308
308
  "path": "CLAUDE.md",
@@ -2582,7 +2582,7 @@
2582
2582
  {
2583
2583
  "path": "docs/module-api-changelog.md",
2584
2584
  "mode": "0000644",
2585
- "sha256": "6c3496a323791d9b6bfc8e86faba4e433a51091e5a9d12b85ede0b207d8057a5"
2585
+ "sha256": "9c1f78d5dc54fdd2b6d62922778e01dbb465005ac689526f7fc327cb977f416b"
2586
2586
  },
2587
2587
  {
2588
2588
  "path": "docs/modules-contract.md",
@@ -2847,7 +2847,7 @@
2847
2847
  {
2848
2848
  "path": "docs/recipes/windows-builders.md",
2849
2849
  "mode": "0000644",
2850
- "sha256": "85823a0b17b646da4b17596c78819da8e7342f24395dcc2e3ea82b5e07c25cba"
2850
+ "sha256": "dba962c19bf22e5773fd05eb6667581d15f62ecda7292a37f83b12227ad14049"
2851
2851
  },
2852
2852
  {
2853
2853
  "path": "docs/recipes/work-on-a-task-from-your-dev-box.md",
@@ -7907,12 +7907,12 @@
7907
7907
  {
7908
7908
  "path": "package-lock.json",
7909
7909
  "mode": "0000644",
7910
- "sha256": "1e217b4d7975b9c295c2806a83a5817f93fc38a0786a1976fe8ec19aac141b50"
7910
+ "sha256": "36122cd40b437ccc5c77b91e5644e520abc238661e70b3232c8741ded1cdda0a"
7911
7911
  },
7912
7912
  {
7913
7913
  "path": "package.json",
7914
7914
  "mode": "0000644",
7915
- "sha256": "6943316e63bef1a867ea04e705e42a9aa28a50e2cded10e16874899c61f69f03"
7915
+ "sha256": "aa3305048a8974caa7fbb34d88c86c5aa326e7d1f21ed80dc82d0e66a523b04a"
7916
7916
  },
7917
7917
  {
7918
7918
  "path": "public-docs/index.html",
@@ -9852,7 +9852,7 @@
9852
9852
  {
9853
9853
  "path": "src/module-api.js",
9854
9854
  "mode": "0000644",
9855
- "sha256": "d2a5ba427ce014f7940e2757f06541e25275e0c4f59c0b9c5026396c795e41f2"
9855
+ "sha256": "81e4082b5cc1067347973cfe7d4c994a6eb43f3b9e64cb3c3f55fd3eec8fd69c"
9856
9856
  },
9857
9857
  {
9858
9858
  "path": "src/module-loader/catalog.js",
@@ -12154,6 +12154,11 @@
12154
12154
  "mode": "0000644",
12155
12155
  "sha256": "68a429b47a1ca36a41433c0d8c3298a0f54745a19b050675aedba658a2cea0ef"
12156
12156
  },
12157
+ {
12158
+ "path": "tests/markdown_line_endings.mjs",
12159
+ "mode": "0000644",
12160
+ "sha256": "629ee8bb78098296039d174b9ddd460fe86acade39f60c1d9bb5f6be9d13762f"
12161
+ },
12157
12162
  {
12158
12163
  "path": "tests/me_ship_days_bound.mjs",
12159
12164
  "mode": "0000644",
package/.gitattributes CHANGED
@@ -37,6 +37,26 @@
37
37
  # read as environmental noise.
38
38
  *.sql text eol=lf
39
39
 
40
+ # Markdown: pinned for the same reason *.sql above is (task 1003981). Unpinned, every
41
+ # .md fell through `* text=auto`, so a Windows clone with the common core.autocrlf=true
42
+ # got CRLF in the worktree for 834 of the 835 tracked .md files while the index stayed
43
+ # LF. That is not cosmetic: this repo has several tools that read .md AS TEXT and make a
44
+ # decision from what they parse — skill-preflight.js (SKILL.md frontmatter), fitness.js
45
+ # G03, linkify-refs.js, docs-entropy.js, the role-pack guard and the doc-CLI guard. A
46
+ # CRLF-blind reader does not fail loudly; it parses nothing and so reports nothing to
47
+ # check. Measured on task 1003754: skill-preflight's /^---\n/ frontmatter regex matched
48
+ # ZERO of 53 skills, so G03 compared an empty set against an empty set and could not
49
+ # fail. Per-site normalisation (tasks 1003754, 1003935) fixes the reader that was
50
+ # noticed; this rule fixes the class, for the reader nobody has written yet.
51
+ #
52
+ # Renormalisation cost: NONE. Measured before landing — no tracked .md carries CRLF in
53
+ # the INDEX, so `git add --renormalize` stages zero files and no committed byte changes.
54
+ # The rule only changes what checkout WRITES. An existing Windows worktree keeps its
55
+ # CRLF copies (the clean filter already normalises them to LF on add, so `git status`
56
+ # stays quiet); a fresh clone, and any file git rewrites, get LF. To convert an existing
57
+ # checkout in place: `git rm --cached -r . && git reset --hard`.
58
+ *.md text eol=lf
59
+
40
60
  # Future Windows-only wrappers (none today) must be CRLF — cmd.exe/PowerShell
41
61
  # expect it. Declared up front so a later setup-builder.cmd lands correct.
42
62
  *.bat text eol=crlf
@@ -115,9 +135,13 @@ src/bongos/routes/CLAUDE.md merge=otb-regen
115
135
  # `* text=auto` above (index LF, worktree CRLF) the check reported STALE forever on
116
136
  # every Windows checkout while the committed content was already correct. The .json
117
137
  # never had the bug because `*.json text eol=lf` above already pins it; the .md fell
118
- # through to text=auto because no `*.md` rule exists (and none should — pinning all
119
- # 685 tracked .md files would renormalize the whole docs tree for one generated file).
120
- # `*.md` deliberately stays unpinned; only the GENERATED artifact is pinned here.
138
+ # through to text=auto because, at the time, no `*.md` rule existed. This entry's
139
+ # `text eol=lf` is now REDUNDANT with the blanket `*.md text eol=lf` above (task
140
+ # 1003981) — kept because it is load-bearing documentation of WHY the generated pair
141
+ # needs LF, and because tests/git_merge_regen.mjs pins this line's multi-attribute
142
+ # shape. The earlier note here argued *.md should stay unpinned, on the belief that
143
+ # pinning it would renormalize the whole docs tree; that was measured and is false —
144
+ # the index was already uniformly LF, so the blanket rule renormalized nothing.
121
145
  docs/copy-registry.json merge=otb-regen
122
146
  docs/copy-inventory.md merge=otb-regen text eol=lf
123
147
 
@@ -2174,5 +2174,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2174
2174
  landed since 1.19.848 with no explicit bump. run 35269098215. (task 1002620)
2175
2175
  1.19.850 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2176
2176
  landed since 1.19.849 with no explicit bump. run 35271402682. (task 1002620)
2177
+ 1.19.851 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2178
+ landed since 1.19.850 with no explicit bump. run 35273175013. (task 1002620)
2177
2179
  ---------------------------------------------------------------------------
2178
2180
  ```
@@ -214,7 +214,7 @@ caught a real bug during task 1003548, so read its assertion before blaming the
214
214
 
215
215
  - Several hall files (`people.css`, `people.html`, `style.css`, the privacy spec) and every `.claude/skills/*/SKILL.md` are CRLF; `scripts/gds/*.js` and the tests are LF. An exact-string patch must detect the file's EOL before joining lines (`text.includes('\r\n') ? '\r\n' : '\n'`), or the find matches nothing and the edit is a silent no-op (session log 2026-08-24).
216
216
  - A `git diff --stat` that touches every line of a file you barely edited is an EOL flip — check with `git diff --stat --ignore-cr-at-eol`, and restore the original EOL before committing.
217
- - **`copy-inventory.js --check` no longer reds on line endings alone** (task 1003619). It used to: the generator emits LF and the check byte-compared that against a CRLF worktree file, so `/ship-check` showed one permanent red line on every Windows checkout while the committed content was already correct — and a builder who "fixed" it committed a whole-file CRLF diff. `docs/copy-inventory.md` is now pinned `text eol=lf` in `.gitattributes` (its `.json` sibling always was, via `*.json`), and the check compares EOL-blind so an already-CRLF worktree passes without a re-clone. If it reports STALE now, the content really is stale — regenerate, don't reach for `--ignore-cr-at-eol`. Note `*.md` is deliberately NOT pinned repo-wide; only that one generated artifact is.
217
+ - **`copy-inventory.js --check` no longer reds on line endings alone** (task 1003619). It used to: the generator emits LF and the check byte-compared that against a CRLF worktree file, so `/ship-check` showed one permanent red line on every Windows checkout while the committed content was already correct — and a builder who "fixed" it committed a whole-file CRLF diff. `docs/copy-inventory.md` is now pinned `text eol=lf` in `.gitattributes` (its `.json` sibling always was, via `*.json`), and the check compares EOL-blind so an already-CRLF worktree passes without a re-clone. If it reports STALE now, the content really is stale — regenerate, don't reach for `--ignore-cr-at-eol`. Since task 1003981 `*.md` IS pinned repo-wide (`*.md text eol=lf`), so a fresh clone gets LF markdown everywhere and a markdown reader no longer has to be CRLF-aware to be correct. An EXISTING Windows checkout keeps its CRLF copies until git rewrites them — the clean filter still normalises to LF on add, so `git status` stays quiet and nothing is broken; to convert in place, `git rm --cached -r . && git reset --hard`.
218
218
  - **A freshness check compares CONTENT, so route it through `sameContent()`** (`scripts/gds/gen-freshness.js`) rather than `===` on file bytes. A pin is the wrong lever on its own: regenerating never clears a byte-wise red, because the write lands LF and git converts it back on the next checkout. `tests/gen_freshness.mjs` enforces this for the four gated generators; `tests/api_client.mjs` was outside that guard and reported the client STALE forever on Windows until task 1003529 (`index.d.ts` and `README.md` are the two generated client files with no `eol=lf` pin).
219
219
 
220
220
  ## Four Windows traps that make a test lie — all four found in one pass (task 1003529)
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.850",
3
+ "version": "1.19.851",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.850",
9
+ "version": "1.19.851",
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.850",
3
+ "version": "1.19.851",
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
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
71
71
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
72
72
  // the entry to that file. Look for a version's history there, not here.
73
73
  // ---------------------------------------------------------------------------
74
- const CORE_VERSION = '1.19.850'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.851'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
75
75
 
76
76
  // A namespaced logger so a module's log lines are attributable + consistent.
77
77
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -0,0 +1,78 @@
1
+ // tests/markdown_line_endings.mjs — *.md is pinned to LF in .gitattributes (task 1003981).
2
+ //
3
+ // WHAT THIS GUARDS. At least six tools in this repo read a .md file AS TEXT and make a
4
+ // decision from what they parse: skill-preflight.js (SKILL.md frontmatter), fitness.js
5
+ // G03, linkify-refs.js, docs-entropy.js, the role-pack guard and the doc-CLI guard.
6
+ // Before this pin, *.md fell through `* text=auto`, so a Windows clone with the common
7
+ // core.autocrlf=true got CRLF in the worktree for 834 of 835 tracked .md files while the
8
+ // index stayed LF. A CRLF-blind reader does not fail loudly — it parses nothing, and a
9
+ // guard with nothing to compare cannot fail. Measured on task 1003754: skill-preflight's
10
+ // /^---\n/ frontmatter regex matched ZERO of 53 skills, and G03 duly reported
11
+ // "53 skill(s) scanned; 0 declare a machine contract" while staying green.
12
+ //
13
+ // Asserted through GIT ITSELF (`git check-attr`), not by pattern-matching .gitattributes:
14
+ // the pattern semantics are git's, and the failure mode this replaces was precisely a
15
+ // rule that read correctly but did not match what it was believed to match (the
16
+ // root-anchored /CLAUDE.md lesson in tests/git_merge_regen.mjs). Reading the file back
17
+ // would re-assert our own spelling rather than git's resolution of it.
18
+ //
19
+ // Run: node --test tests/markdown_line_endings.mjs
20
+
21
+ import { test } from 'node:test';
22
+ import assert from 'node:assert/strict';
23
+ import { spawnSync } from 'node:child_process';
24
+ import path from 'node:path';
25
+ import { fileURLToPath } from 'node:url';
26
+
27
+ const repo = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
28
+
29
+ const git = (args) => spawnSync('git', args, { cwd: repo, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
30
+
31
+ const eolOf = (p) => {
32
+ const r = git(['check-attr', 'eol', '--', p]);
33
+ return (r.stdout || '').trim().split(': ').pop();
34
+ };
35
+
36
+ // Representative paths, chosen for DEPTH rather than count: a gitattributes pattern
37
+ // with no leading slash matches at any depth, and the bug being pinned bit a .md
38
+ // four directories down, not one at the root.
39
+ test('every tracked .md resolves to eol=lf, at any depth', () => {
40
+ for (const p of [
41
+ 'README.md',
42
+ 'CLAUDE.md',
43
+ 'docs/architecture.md',
44
+ 'docs/packs/engineer.md',
45
+ 'docs/adr/README.md',
46
+ '.claude/skills/merge-mode/SKILL.md',
47
+ 'modules/hall-ui/CLAUDE.md',
48
+ ]) {
49
+ assert.equal(eolOf(p), 'lf', `${p} must be pinned to LF — a CRLF copy silently voids every reader that parses it`);
50
+ }
51
+ });
52
+
53
+ // The invariant that actually matters, over the REAL tracked set rather than a sample.
54
+ // `git ls-files --eol` reports the index ("i/") and worktree ("w/") encodings side by
55
+ // side; the index is what every clone receives, so an index CRLF is the state that
56
+ // would ship the bug to someone else's checkout.
57
+ test('no tracked .md carries CRLF in the index', () => {
58
+ const r = git(['ls-files', '--eol', '-z', '*.md']);
59
+ assert.equal(r.status, 0, 'git ls-files --eol must succeed');
60
+ const rows = (r.stdout || '').split('\0').filter(Boolean);
61
+ assert.ok(rows.length > 500, `expected the full markdown set, got ${rows.length} rows`);
62
+
63
+ const crlf = rows.filter((row) => /^i\/crlf/.test(row.trim())).map((row) => row.trim());
64
+ assert.deepEqual(crlf, [], `these .md files are CRLF in the index: ${crlf.join(', ')}`);
65
+ });
66
+
67
+ // The complementary half, and the reason this is not just `*` pinned to LF: the repo
68
+ // deliberately ships CRLF for the Windows-shell wrappers, where cmd.exe and PowerShell
69
+ // expect it. A future over-broad edit that pinned everything to LF would silently break
70
+ // those, and the markdown assertions above would keep passing while it did.
71
+ test('the Windows-shell classes stay pinned to CRLF', () => {
72
+ // scripts/gds/api.ps1 is the one such file that exists today; the .cmd/.bat spellings
73
+ // are the declared-up-front rules for the wrappers .gitattributes says do not exist yet.
74
+ // check-attr resolves a PATTERN, so it answers for those too — which is the point here.
75
+ for (const p of ['scripts/gds/api.ps1', 'scripts/setup-builder.cmd', 'scripts/setup-builder.bat']) {
76
+ assert.equal(eolOf(p), 'crlf', `${p} must stay CRLF — cmd.exe/PowerShell expect it`);
77
+ }
78
+ });