@bongos/core 1.19.633 → 1.19.635

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.633",
6
- "core_contract": "1.19.633",
7
- "source_commit": "8a560f46851725a2db7c987576b636af9054138e",
5
+ "core_version": "1.19.635",
6
+ "core_contract": "1.19.635",
7
+ "source_commit": "c97f3015861c4ca09d2c5a07f78ab33284d7c26c",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-09T23:38:22.332Z",
9
+ "built_at": "2026-09-10T02:33:59.187Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 468,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 2591,
20
- "tree_sha256": "a7e9c16628645ccc819cbdbf1f77115bf6b14faaa2e04f9c019680d0ab321d1a",
20
+ "tree_sha256": "c5c9267a793145efe19a63442cfbe05ee6cf03d5c6ff363084857bf151aec4cc",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/backlog-review/SKILL.md",
@@ -2777,7 +2777,7 @@
2777
2777
  {
2778
2778
  "path": "docs/module-api-changelog.md",
2779
2779
  "mode": "0000644",
2780
- "sha256": "9be51df76afca08c558e77044a4206b75cc51f30cddeb72a248030bd878c6541"
2780
+ "sha256": "baa05168e88c98e3fc35c1bf652bd85ef90dcfb463408c68e5132910316f8c34"
2781
2781
  },
2782
2782
  {
2783
2783
  "path": "docs/modules-contract.md",
@@ -7707,12 +7707,12 @@
7707
7707
  {
7708
7708
  "path": "package-lock.json",
7709
7709
  "mode": "0000644",
7710
- "sha256": "c0fc65fd1a4de740e7e68cbba9bc6ea3a3fa951ce373d3f79a4f829837ee0e78"
7710
+ "sha256": "f40ca54ae7693ccd7a41bb2429fa61f71b147f0aabc821535e4ca6e9055d9f49"
7711
7711
  },
7712
7712
  {
7713
7713
  "path": "package.json",
7714
7714
  "mode": "0000644",
7715
- "sha256": "49f18e7b79579bd167d9a705afb40cbb99f67bf71b8118ccbbddfb306e15f740"
7715
+ "sha256": "1d7c9b3ad4172d3702cd4baa6fd5f30d1c26bedcfdcea6e8c2532d0decb9814e"
7716
7716
  },
7717
7717
  {
7718
7718
  "path": "public-docs/index.html",
@@ -9312,7 +9312,7 @@
9312
9312
  {
9313
9313
  "path": "src/bongos/route-rank-check.js",
9314
9314
  "mode": "0000644",
9315
- "sha256": "ad2d07652864d577736f6c0f83e27ff197fe2201796eb06c5577743c16119a5b"
9315
+ "sha256": "514f9bb73cc74a2574272b733e0314dfe3b372497874bd7c88b763f22ddab64e"
9316
9316
  },
9317
9317
  {
9318
9318
  "path": "src/bongos/routes.js",
@@ -9452,7 +9452,7 @@
9452
9452
  {
9453
9453
  "path": "src/module-api.js",
9454
9454
  "mode": "0000644",
9455
- "sha256": "833f00528d9bc449a51caa1a3ac924b866d1a054f89faf45bebf49d0b62be156"
9455
+ "sha256": "79ef2ff7f2ac145450cc27389e4da2edd8079f2887ba7240c057e0e8cb8bb198"
9456
9456
  },
9457
9457
  {
9458
9458
  "path": "src/module-loader/catalog.js",
@@ -12202,7 +12202,7 @@
12202
12202
  {
12203
12203
  "path": "tests/route_rank_check.mjs",
12204
12204
  "mode": "0000644",
12205
- "sha256": "bdc58224050392ece492ae8e8f12f62a8934d86e3993e0df5b8cb0aac80602e8"
12205
+ "sha256": "9fd3762c6b171ee39b0cee336de2d41547795b2cd4898b178325cfdd321cf28a"
12206
12206
  },
12207
12207
  {
12208
12208
  "path": "tests/route_shadow_guard.mjs",
@@ -1715,5 +1715,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
1715
1715
  landed since 1.19.631 with no explicit bump. run 34417373737. (task 1002620)
1716
1716
  1.19.633 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1717
1717
  landed since 1.19.632 with no explicit bump. run 34417769106. (task 1002620)
1718
+ 1.19.634 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1719
+ landed since 1.19.633 with no explicit bump. run 34429621784. (task 1002620)
1720
+ 1.19.635 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1721
+ landed since 1.19.634 with no explicit bump. run 34429906252. (task 1002620)
1718
1722
  ---------------------------------------------------------------------------
1719
1723
  ```
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.633",
3
+ "version": "1.19.635",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.633",
9
+ "version": "1.19.635",
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.633",
3
+ "version": "1.19.635",
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",
@@ -517,6 +517,61 @@ function rankFromRankGate(tail) {
517
517
  return null;
518
518
  }
519
519
 
520
+ // The source text of ONE route declaration — `router.X(` through its matching `)`.
521
+ //
522
+ // Why this exists (task 1003190, from the task-1002671 adversarial verification):
523
+ // a route's middleware list IS its parenthesised argument list, so the honest bound
524
+ // on "what gates this route" is the declaration's own paren balance. Every earlier
525
+ // bound was a heuristic tail that cut at the next thing RESEMBLING a sibling, which
526
+ // meant anything between the route and that marker still read as this route's gate.
527
+ // Three shapes got through, each certifying an UNGATED route as gated with real
528
+ // `via:'middleware'` provenance — passing the ungated-write blocker and satisfying
529
+ // the EXPECTED_RANKS pins (the task-1002553 fix only stops `via:'annotation'`):
530
+ // 1. a non-route gate below it — `const guard = auth.requirePermission('…')`
531
+ // 2. an inline classic handler — `function (req, res) {` never matches `=> {`
532
+ // 3. a middleware array below it — `const chain = [auth.requireRank('archon')]`
533
+ // Shape 1 is the general case: task 1003062's next-`router.` clamp closed only the
534
+ // sibling-ROUTE spelling of it, so the originally-filed repro no longer reproduces
535
+ // while the hole itself stayed open.
536
+ //
537
+ // Scans quote-, template- and comment-aware so a `)` inside a route path, a string
538
+ // default, or a comment cannot end the span early. Returns the whole text unchanged
539
+ // when the opening `(` is absent or never closes inside the window — an unbalanced
540
+ // declaration is not evidence of a narrower gate, so the caller keeps its prior
541
+ // (wider, fail-loud) view rather than silently trusting a truncation.
542
+ function declarationSpan(text) {
543
+ const open = text.search(/router\.(get|post|patch|put|delete|use)\s*\(/);
544
+ if (open === -1) return text;
545
+ const start = text.indexOf('(', open);
546
+ if (start === -1) return text;
547
+
548
+ let depth = 0;
549
+ let quote = null; // "'" | '"' | '`' when inside a string/template
550
+ let comment = null; // 'line' | 'block'
551
+ for (let k = start; k < text.length; k++) {
552
+ const c = text[k];
553
+ const next = text[k + 1];
554
+
555
+ if (comment === 'line') { if (c === '\n') comment = null; continue; }
556
+ if (comment === 'block') { if (c === '*' && next === '/') { comment = null; k++; } continue; }
557
+ if (quote) {
558
+ if (c === '\\') { k++; continue; }
559
+ if (c === quote) quote = null;
560
+ continue;
561
+ }
562
+ if (c === '/' && next === '/') { comment = 'line'; k++; continue; }
563
+ if (c === '/' && next === '*') { comment = 'block'; k++; continue; }
564
+ if (c === "'" || c === '"' || c === '`') { quote = c; continue; }
565
+
566
+ if (c === '(') depth++;
567
+ else if (c === ')') {
568
+ depth--;
569
+ if (depth === 0) return text.slice(0, k + 1);
570
+ }
571
+ }
572
+ return text;
573
+ }
574
+
520
575
  // Classify one route's gate from the source lines and the declaration index.
521
576
  // Returns { rank, perms, via } — `perms` is the permission atoms the route names, or
522
577
  // null when it carries no permission gate; `via` is the PROVENANCE of the label:
@@ -555,8 +610,14 @@ function classifyGate(lines, i, { floors } = {}) {
555
610
  // common because the fitness oversize ratchet pushes handler bodies out of large
556
611
  // route files, so this is not an exotic shape. A window must never cross into a
557
612
  // sibling declaration.
558
- const nextRouteAt = window.search(/\n\s*router\.(get|post|patch|put|delete|use)\s*\(/);
559
- const own = nextRouteAt === -1 ? window : window.slice(0, nextRouteAt);
613
+ // task 1003190: the two clamps above are both HEURISTIC TAILS — they cut at the
614
+ // next thing that looks like a sibling, so anything between the route and that
615
+ // sibling is still read as this route's middleware. `declarationSpan` replaces
616
+ // the guesswork with the real bound: the declaration's own parenthesis balance.
617
+ // A route's middleware list is, by definition, the arguments inside `router.X(
618
+ // … )`; nothing after the matching `)` can be a gate on THIS route. See that
619
+ // function's header for the three shapes the heuristics let through.
620
+ const own = declarationSpan(window);
560
621
  const handlerAt = own.search(/=>\s*\{/);
561
622
  const tail = handlerAt === -1 ? own : own.slice(0, handlerAt);
562
623
 
package/src/module-api.js CHANGED
@@ -55,7 +55,7 @@ const { buildInfo } = require('./build-info');
55
55
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
56
56
  // the entry to that file. Look for a version's history there, not here.
57
57
  // ---------------------------------------------------------------------------
58
- const CORE_VERSION = '1.19.633'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
58
+ const CORE_VERSION = '1.19.635'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
59
59
 
60
60
  // A namespaced logger so a module's log lines are attributable + consistent.
61
61
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -80,6 +80,78 @@ test('a route declared with NO middleware does not borrow the NEXT route\'s rank
80
80
  assert.equal(rows.find((x) => x.method === 'POST').rank, 'archon');
81
81
  });
82
82
 
83
+ // ---------- task 1003190: the bound is the DECLARATION, not a heuristic tail ----------
84
+ //
85
+ // From the task-1002671 adversarial verification (finding 1). The bleed above is only
86
+ // the sibling-ROUTE spelling; task 1003062 closed that one by clamping at the next
87
+ // `router.` declaration. But the clamp is still a heuristic TAIL — it cuts at the next
88
+ // thing RESEMBLING a sibling, so any gate-shaped text BEFORE that marker was still read
89
+ // as this route's middleware. Each case below is an UNGATED write that classified as
90
+ // gated with real `via:'middleware'` provenance — which passes the ungated-write blocker
91
+ // AND satisfies the EXPECTED_RANKS pins (the task-1002553 fix only stops
92
+ // `via:'annotation'`). `declarationSpan` bounds the tail by paren balance instead, so
93
+ // nothing after the declaration's matching `)` can be mistaken for its gate.
94
+ //
95
+ // The assertion that matters in each is `via`: 'unknown'/null is the auditor admitting
96
+ // it cannot verify a gate (a blocker on a write route — loud, correct), whereas the bug
97
+ // produced a confident, wrong 'middleware'.
98
+
99
+ test('a named-function handler does not absorb a NON-ROUTE gate below it [task 1003190]', () => {
100
+ // The general case task 1003062's next-`router.` clamp does not reach: the gate-shaped
101
+ // text is a plain const, so there is no sibling declaration to clamp at.
102
+ const src = `router.post('/ungated-write', handleUngatedWrite);\n` +
103
+ `\n` +
104
+ `const guard = auth.requirePermission('government.manage');\n`;
105
+ const row = rrc.classifyText(src)[0];
106
+ assert.equal(row.rank, 'unknown');
107
+ assert.equal(row.via, null);
108
+ assert.equal(row.perms, null); // must NOT inherit government.manage
109
+ });
110
+
111
+ test('an inline CLASSIC function handler does not absorb a trailing gate [task 1003190]', () => {
112
+ // `function (req, res) {` never matches the `=> {` truncation, so before this fix the
113
+ // classifier fell through to the full 20-line window.
114
+ const src = `router.post('/ungated-write', function (req, res) {\n` +
115
+ ` res.end();\n` +
116
+ `});\n` +
117
+ `const guard = auth.requireRank('archon');\n`;
118
+ const row = rrc.classifyText(src)[0];
119
+ assert.equal(row.rank, 'unknown');
120
+ assert.equal(row.via, null);
121
+ });
122
+
123
+ test('a named-function handler does not absorb a middleware ARRAY below it [task 1003190]', () => {
124
+ const src = `router.post('/ungated-write', handleUngatedWrite);\n` +
125
+ `const chain = [auth.requireRank('archon')];\n`;
126
+ const row = rrc.classifyText(src)[0];
127
+ assert.equal(row.rank, 'unknown');
128
+ assert.equal(row.via, null);
129
+ });
130
+
131
+ test('a REAL multi-line middleware list is still read in full [task 1003190]', () => {
132
+ // The counter-test: bounding by paren balance must not truncate a legitimate gate that
133
+ // spans several lines. Without this, the fix above could "pass" by blinding the auditor.
134
+ const src = `router.post(\n` +
135
+ ` '/gated',\n` +
136
+ ` auth.requireBuilder,\n` +
137
+ ` auth.requirePermission('government.manage'),\n` +
138
+ ` async (req, res) => {\n` +
139
+ ` res.end();\n },\n);`;
140
+ const row = rrc.classifyText(src)[0];
141
+ assert.equal(row.via, 'middleware');
142
+ assert.deepEqual(row.perms, ['government.manage']);
143
+ });
144
+
145
+ test('a gate inside a route PATH or string cannot be ended early by its parens [task 1003190]', () => {
146
+ // declarationSpan is quote-aware: a `)` inside the path string must not close the span
147
+ // before the real middleware is seen.
148
+ const src = `router.get('/re/(x)/y', auth.requireRank('archon'), async (req, res) => {\n` +
149
+ ` res.end();\n});`;
150
+ const row = rrc.classifyText(src)[0];
151
+ assert.equal(row.rank, 'archon');
152
+ assert.equal(row.via, 'middleware');
153
+ });
154
+
83
155
  // ---------- BV1.R109b: multi-line route DECLARATIONS are visible at all ----------
84
156
  //
85
157
  // Distinct from the "multi-line middleware" test above: there the METHOD AND PATH were