@bongos/core 1.19.183 → 1.19.184

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.
Files changed (63) hide show
  1. package/.bongos-core.json +80 -75
  2. package/docs/api/openapi.json +9 -9
  3. package/modules/{governance → government}/catalog.js +1 -1
  4. package/modules/{governance → government}/config.js +6 -6
  5. package/modules/{governance → government}/db.js +43 -43
  6. package/modules/government/migrations/government_001_rename_from_governance.sql +213 -0
  7. package/modules/government/module.json +22 -0
  8. package/modules/{governance → government}/protected-surfaces.json +1 -1
  9. package/modules/{governance/rank-roles.js → government/ranks.js} +9 -9
  10. package/modules/{governance → government}/routes/governance.js +5 -5
  11. package/modules/{governance/routes/role-sync.js → government/routes/rank-sync.js} +7 -7
  12. package/modules/lifecycle/db.js +6 -6
  13. package/package-lock.json +2 -2
  14. package/package.json +1 -1
  15. package/scripts/gds/fitness.js +11 -1
  16. package/scripts/gds/migration-namespace.js +15 -3
  17. package/scripts/gds/publish-manifest.js +3 -2
  18. package/scripts/gds/seed-governance-tasks.js +2 -2
  19. package/src/bongos/auth.js +9 -9
  20. package/src/bongos/db.js +6 -6
  21. package/src/bongos/permission-path-check.js +3 -3
  22. package/src/bongos/route-rank-check.js +3 -3
  23. package/src/module-api.js +4 -2
  24. package/tests/auth_page_gate.mjs +2 -2
  25. package/tests/criterion_authoring_gate.mjs +1 -1
  26. package/tests/governance_abuse_matrix.mjs +7 -7
  27. package/tests/governance_catalog.mjs +1 -1
  28. package/tests/governance_claim_eligibility.mjs +1 -1
  29. package/tests/governance_config.mjs +7 -7
  30. package/tests/governance_fold.mjs +4 -4
  31. package/tests/governance_live_proof.mjs +2 -2
  32. package/tests/governance_ownership_scope.mjs +1 -1
  33. package/tests/governance_page_gates.mjs +6 -6
  34. package/tests/governance_parity.mjs +3 -3
  35. package/tests/governance_principals.mjs +1 -1
  36. package/tests/governance_protected_surfaces.mjs +3 -3
  37. package/tests/governance_require_permission.mjs +6 -6
  38. package/tests/governance_resolver.mjs +2 -2
  39. package/tests/governance_role_sync.mjs +14 -14
  40. package/tests/governance_routes.mjs +6 -6
  41. package/tests/governance_seed.mjs +11 -3
  42. package/tests/governance_session_scope.mjs +1 -1
  43. package/tests/governance_vanilla_boot.mjs +4 -4
  44. package/tests/hall_page_gate_map.mjs +1 -1
  45. package/tests/memory_isolation.mjs +2 -2
  46. package/tests/module_loader.mjs +1 -1
  47. package/tests/onboarding_observability.mjs +2 -2
  48. package/tests/rank_tier_single_source.mjs +2 -2
  49. package/tests/route_permission_check.mjs +2 -2
  50. package/modules/governance/module.json +0 -11
  51. /package/config/{governance.neutral.json → government.neutral.json} +0 -0
  52. /package/modules/{governance → government}/CLAUDE.md +0 -0
  53. /package/modules/{governance → government}/migrations/governance_001_tables.sql +0 -0
  54. /package/modules/{governance → government}/migrations/governance_002_seed_and_backfill.sql +0 -0
  55. /package/modules/{governance → government}/migrations/governance_003_task_abandon_metic.sql +0 -0
  56. /package/modules/{governance → government}/migrations/governance_004_criterion_create.sql +0 -0
  57. /package/modules/{governance → government}/migrations/governance_005_resync_builder_rank_roles.sql +0 -0
  58. /package/modules/{governance → government}/migrations/governance_006_version_create.sql +0 -0
  59. /package/modules/{governance → government}/migrations/governance_007_delegate_archon_ops_to_metic.sql +0 -0
  60. /package/modules/{governance → government}/protected-surfaces.js +0 -0
  61. /package/modules/{governance → government}/resolver.js +0 -0
  62. /package/modules/{governance → government}/session-scopes.js +0 -0
  63. /package/modules/{governance → government}/session-scopes.json +0 -0
@@ -8,7 +8,7 @@
8
8
  //
9
9
  // The load-bearing test is BEHAVIOR-IDENTITY. R101 moved WHERE the truth lives
10
10
  // (a hardcoded PROTECTED_GLOBS constant in src/bongos/permission-path-check.js →
11
- // governance-owned data in modules/governance/protected-surfaces.json). It did
11
+ // governance-owned data in modules/government/protected-surfaces.json). It did
12
12
  // NOT change WHAT is protected. EXPECTED_GLOBS_BEFORE_R101 below is the literal
13
13
  // pre-change constant, pasted verbatim; the registry must reproduce it exactly,
14
14
  // in order.
@@ -22,7 +22,7 @@ import { fileURLToPath } from 'node:url';
22
22
 
23
23
  const require = createRequire(import.meta.url);
24
24
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
25
- const GOV = path.join(ROOT, 'modules', 'governance');
25
+ const GOV = path.join(ROOT, 'modules', 'government');
26
26
 
27
27
  const ppc = require(path.join(ROOT, 'src', 'bongos', 'permission-path-check.js'));
28
28
  const registry = require(path.join(GOV, 'protected-surfaces.js'));
@@ -234,7 +234,7 @@ test('a known path is protected at the right floor; an unknown path is not', ()
234
234
  assert.equal(ppc.floorFor('src/bongos/auth.js'), 'metic');
235
235
  assert.equal(ppc.permissionFor('src/bongos/auth.js'), 'path.protected.modify');
236
236
  assert.equal(registry.isProtected('migrations/999_x.sql'), true, 'subtree globs still match');
237
- assert.equal(registry.floorFor('modules/governance/catalog.js'), 'metic');
237
+ assert.equal(registry.floorFor('modules/government/catalog.js'), 'metic');
238
238
 
239
239
  assert.equal(ppc.floorFor('public/game/main.js'), null);
240
240
  assert.equal(ppc.permissionFor('docs/session-logs/2026-07-30-x.md'), null);
@@ -1,7 +1,7 @@
1
1
  // tests/governance_require_permission.mjs — the requirePermission gate (BV1.R97, ADR 0151).
2
2
  //
3
3
  // DB-free. The gate reaches the resolver through the `governance` KERNEL PORT
4
- // (the one-way rule — core never requires modules/governance/), so a stub
4
+ // (the one-way rule — core never requires modules/government/), so a stub
5
5
  // provider registered on the seam is the whole test double: no Postgres, no
6
6
  // router, no live module. That is also the point being asserted — if auth.js ever
7
7
  // went back to importing the module directly, these tests could not stub it.
@@ -23,7 +23,7 @@ const auth = require(path.join(ROOT, 'src', 'bongos', 'auth.js'));
23
23
  const seams = require(path.join(ROOT, 'src', 'module-seams.js'));
24
24
  const { attachFail } = require(path.join(ROOT, 'src', 'bongos', 'middleware', 'error-envelope.js'));
25
25
  const { classify } = require(path.join(ROOT, 'src', 'bongos', 'api-errors.js'));
26
- const catalog = require(path.join(ROOT, 'modules', 'governance', 'catalog.js'));
26
+ const catalog = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
27
27
 
28
28
  // Minimal res double capturing status + body, with res.fail() installed exactly
29
29
  // as the router installs it (mirrors tests/rank_gate.mjs).
@@ -42,7 +42,7 @@ function fakeRes() {
42
42
  // resolveBuilderPermissions; pass null to leave the port UNREGISTERED.
43
43
  async function run(gate, req, resolve) {
44
44
  seams._reset();
45
- if (resolve !== null) seams.registerProvider('governance', { resolveBuilderPermissions: resolve });
45
+ if (resolve !== null) seams.registerProvider('government', { resolveBuilderPermissions: resolve });
46
46
  const res = fakeRes();
47
47
  let nexted = false;
48
48
  await gate(req, res, () => { nexted = true; });
@@ -89,7 +89,7 @@ test('the denial names the floor rank, not just the atom (task 1002613, map P-1)
89
89
  // this test moves WITH a floor change instead of pinning stale prose — the
90
90
  // D-16/N-3 failure shape the fix exists to avoid.
91
91
  seams._reset();
92
- seams.registerProvider('governance', {
92
+ seams.registerProvider('government', {
93
93
  resolveBuilderPermissions: holding('idea.triage'),
94
94
  permissionFloor: (key) => (catalog.byKey(key) || {}).floor || null,
95
95
  });
@@ -143,7 +143,7 @@ test('an UNREGISTERED governance port denies, it does not admit', async () => {
143
143
 
144
144
  test('a malformed port (no resolveBuilderPermissions) denies', async () => {
145
145
  seams._reset();
146
- seams.registerProvider('governance', { isSystem: () => true });
146
+ seams.registerProvider('government', { isSystem: () => true });
147
147
  const res = fakeRes();
148
148
  let nexted = false;
149
149
  await auth.requirePermission('idea.triage')({ builder: BUILDER }, res, () => { nexted = true; });
@@ -175,7 +175,7 @@ test('the gate resolves per request — no memoised authority (ADR 0016)', async
175
175
  let calls = 0;
176
176
  let keys = ['idea.triage'];
177
177
  seams._reset();
178
- seams.registerProvider('governance', { resolveBuilderPermissions: async () => { calls += 1; return keys; } });
178
+ seams.registerProvider('government', { resolveBuilderPermissions: async () => { calls += 1; return keys; } });
179
179
  const gate = auth.requirePermission('idea.triage');
180
180
  const first = fakeRes();
181
181
  let admitted = false;
@@ -16,7 +16,7 @@ import { fileURLToPath } from 'node:url';
16
16
 
17
17
  const require = createRequire(import.meta.url);
18
18
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
19
- const GOV = path.join(ROOT, 'modules', 'governance');
19
+ const GOV = path.join(ROOT, 'modules', 'government');
20
20
  const resolver = require(path.join(GOV, 'resolver.js'));
21
21
  const catalog = require(path.join(GOV, 'catalog.js'));
22
22
  const { effectivePermissions, resolveBuilderPermissions, builderHasPermissions } = resolver;
@@ -79,6 +79,6 @@ test('the kernel port exposes the resolver without core importing the module', (
79
79
  assert.equal(typeof governancePort.builderHasPermissions, 'function');
80
80
  assert.equal(typeof governancePort.isSystem, 'function');
81
81
  const manifest = JSON.parse(fs.readFileSync(path.join(GOV, 'module.json'), 'utf8'));
82
- assert.ok(manifest.provides.includes('governance'), 'module.json must declare the governance port');
82
+ assert.ok(manifest.provides.includes('government'), 'module.json must declare the government port');
83
83
  assert.ok(manifest.contributes.routes.includes('governance'), 'the port registers from the route factory');
84
84
  });
@@ -1,8 +1,8 @@
1
1
  // tests/governance_role_sync.mjs — rank→role assignment stays in sync (BV1.R95b, ADR 0151).
2
2
  //
3
- // DB-free. The decision the writer executes is a pure function (modules/governance/
4
- // rank-roles.js planRankRoleSync), so these exercise PRODUCTION logic directly rather
5
- // than a re-implementation: db.syncRankRole reads the two row sets, calls this exact
3
+ // DB-free. The decision the writer executes is a pure function (modules/government/
4
+ // ranks.js planRankSync), so these exercise PRODUCTION logic directly rather
5
+ // than a re-implementation: db.syncRank reads the two row sets, calls this exact
6
6
  // function, and executes its verdict. The SQL halves — the DELETE/INSERT the writer
7
7
  // issues and the repair migration — are asserted structurally.
8
8
  //
@@ -21,8 +21,8 @@ import { fileURLToPath } from 'node:url';
21
21
 
22
22
  const require = createRequire(import.meta.url);
23
23
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
24
- const GOV = path.join(ROOT, 'modules', 'governance');
25
- const { planRankRoleSync, isSeededRankRole } = require(path.join(GOV, 'rank-roles.js'));
24
+ const GOV = path.join(ROOT, 'modules', 'government');
25
+ const { planRankSync, isSeededRank } = require(path.join(GOV, 'ranks.js'));
26
26
 
27
27
  // The seeded rank-roles exactly as governance_002 writes them.
28
28
  const SEEDED = [
@@ -35,7 +35,7 @@ const seededRole = (rank) => ({ role_key: rank, seeded_rank: rank, is_system: tr
35
35
  // An Archon-authored custom role from the R110 tab: no seeded_rank, not a system role.
36
36
  const customRole = (key) => ({ role_key: key, seeded_rank: null, is_system: false });
37
37
 
38
- const plan = (rank, currentRoles) => planRankRoleSync({ rank, currentRoles, seededRoles: SEEDED });
38
+ const plan = (rank, currentRoles) => planRankSync({ rank, currentRoles, seededRoles: SEEDED });
39
39
 
40
40
  // ---------------------------------------------------------------------------
41
41
  // registration — a builder with no roles gets the one matching their rank
@@ -118,7 +118,7 @@ test('a custom role is not mistaken for the rank-role even when its key matches
118
118
  // role_key is UNIQUE so this cannot happen today, but the predicate must key on
119
119
  // is_system + seeded_rank rather than on the key's spelling.
120
120
  const impostor = { role_key: 'archon', seeded_rank: null, is_system: false };
121
- assert.equal(isSeededRankRole(impostor), false);
121
+ assert.equal(isSeededRank(impostor), false);
122
122
  const p = plan('metic', [impostor]);
123
123
  assert.deepEqual([...p.remove], [], 'a non-system role is never rotated away');
124
124
  });
@@ -147,7 +147,7 @@ test('the sync is idempotent — running it twice changes nothing the second tim
147
147
  const first = plan('metic', [seededRole('archon')]);
148
148
  assert.ok(first.add.length + first.remove.length > 0, 'the first run must do work');
149
149
  const after = first.next.map((key) => (SEEDED.find((s) => s.role_key === key) || customRole(key)));
150
- const second = planRankRoleSync({ rank: 'metic', currentRoles: after, seededRoles: SEEDED });
150
+ const second = planRankSync({ rank: 'metic', currentRoles: after, seededRoles: SEEDED });
151
151
  assert.deepEqual([...second.add], []);
152
152
  assert.deepEqual([...second.remove], []);
153
153
  assert.deepEqual([...second.next], [...first.next]);
@@ -175,15 +175,15 @@ const repairSql = fs.readFileSync(path.join(migDir, 'governance_005_resync_build
175
175
  const stripSqlComments = (sql) => sql.replace(/--[^\n]*/g, '');
176
176
 
177
177
  test('the writer DELETEs the superseded assignments, not just INSERTs the new one', () => {
178
- assert.match(dbSrc, /DELETE FROM governance_builder_roles/,
179
- 'syncRankRole must delete superseded rank-roles — an additive-only writer preserves privilege retention');
180
- assert.match(dbSrc, /INSERT INTO governance_builder_roles[\s\S]*ON CONFLICT \(builder_id, role_key\) DO NOTHING/,
178
+ assert.match(dbSrc, /DELETE FROM government_builder_ranks/,
179
+ 'syncRank must delete superseded rank-roles — an additive-only writer preserves privilege retention');
180
+ assert.match(dbSrc, /INSERT INTO government_builder_ranks[\s\S]*ON CONFLICT \(builder_id, rank_key\) DO NOTHING/,
181
181
  'the assignment insert must be idempotent');
182
182
  });
183
183
 
184
184
  test('the writer runs on the CALLER\'s transaction client when given one', () => {
185
- assert.match(dbSrc, /async function syncRankRole\(client,/,
186
- 'syncRankRole must take the caller\'s client so the rotation is atomic with the rank write');
185
+ assert.match(dbSrc, /async function syncRank\(client,/,
186
+ 'syncRank must take the caller\'s client so the rotation is atomic with the rank write');
187
187
  assert.match(dbSrc, /const q = client \|\| pool;/,
188
188
  'and fall back to the pool only when there is no surrounding transaction');
189
189
  });
@@ -197,7 +197,7 @@ test('both rank-change twins rotate the role inside their transaction', () => {
197
197
  assert.ok(upd !== -1, `${rel}: expected the rank UPDATE in _applyRankChangeTx`);
198
198
  assert.ok(sync !== -1, `${rel}: the rank write must rotate the seeded rank-role`);
199
199
  assert.ok(sync > upd, `${rel}: the rotation must follow the rank write inside the same transaction`);
200
- assert.match(src, /resolveOptional\('governance\.roleSync'\)/,
200
+ assert.match(src, /resolveOptional\('government\.rankSync'\)/,
201
201
  `${rel}: must reach governance through the kernel port, never by importing the module`);
202
202
  }
203
203
  });
@@ -33,13 +33,13 @@ const require = createRequire(import.meta.url);
33
33
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
34
34
  const api = require(path.join(ROOT, 'src', 'module-api.js'));
35
35
  const seams = require(path.join(ROOT, 'src', 'module-seams.js'));
36
- const catalog = require(path.join(ROOT, 'modules', 'governance', 'catalog.js'));
37
- const govDb = require(path.join(ROOT, 'modules', 'governance', 'db.js'));
36
+ const catalog = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
37
+ const govDb = require(path.join(ROOT, 'modules', 'government', 'db.js'));
38
38
  const rrc = require(path.join(ROOT, 'src', 'bongos', 'route-rank-check.js'));
39
39
  const { attachFail } = require(path.join(ROOT, 'src', 'bongos', 'middleware', 'error-envelope.js'));
40
40
  const express = require('express');
41
41
 
42
- const ROUTES_SRC = path.join(ROOT, 'modules', 'governance', 'routes', 'governance.js');
42
+ const ROUTES_SRC = path.join(ROOT, 'modules', 'government', 'routes', 'governance.js');
43
43
 
44
44
  // ===========================================================================
45
45
  // Layer 1 — gate classification + route-rank-check pins
@@ -88,7 +88,7 @@ test('every declared /governance route is pinned, and every pin exists (both dir
88
88
 
89
89
  test('checkRouteRanks passes over the real tree (no governance findings)', () => {
90
90
  const result = rrc.checkRouteRanks();
91
- const ours = result.findings.filter((f) => String(f.file).includes('modules/governance/'));
91
+ const ours = result.findings.filter((f) => String(f.file).includes('modules/government/'));
92
92
  assert.deepEqual(ours, [], `governance findings: ${JSON.stringify(ours, null, 2)}`);
93
93
  });
94
94
 
@@ -131,11 +131,11 @@ api.requireBuilder = (req, res, next) => { req.builder = { id: 42, rank: 'archon
131
131
 
132
132
  function grant(keys) {
133
133
  seams._reset();
134
- seams.registerProvider('governance', { resolveBuilderPermissions: async () => keys });
134
+ seams.registerProvider('government', { resolveBuilderPermissions: async () => keys });
135
135
  }
136
136
  grant(['governance.manage']);
137
137
 
138
- const buildGovernanceRouter = require(path.join(ROOT, 'modules', 'governance', 'routes', 'governance.js'));
138
+ const buildGovernanceRouter = require(path.join(ROOT, 'modules', 'government', 'routes', 'governance.js'));
139
139
  const app = express();
140
140
  app.use(express.json());
141
141
  app.use(attachFail);
@@ -15,9 +15,9 @@ import { fileURLToPath } from 'node:url';
15
15
 
16
16
  const require = createRequire(import.meta.url);
17
17
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
18
- const { RANK_ROLE_SEED, RANK_ORDER } = require(path.join(ROOT, 'modules', 'governance', 'catalog.js'));
18
+ const { RANK_ROLE_SEED, RANK_ORDER } = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
19
19
 
20
- const MIG_DIR = path.join(ROOT, 'modules', 'governance', 'migrations');
20
+ const MIG_DIR = path.join(ROOT, 'modules', 'government', 'migrations');
21
21
  const seedSql = fs.readFileSync(path.join(MIG_DIR, 'governance_002_seed_and_backfill.sql'), 'utf8');
22
22
  const tablesSql = fs.readFileSync(path.join(MIG_DIR, 'governance_001_tables.sql'), 'utf8');
23
23
 
@@ -28,8 +28,16 @@ const tablesSql = fs.readFileSync(path.join(MIG_DIR, 'governance_001_tables.sql'
28
28
  // ADR 0152), and what must equal RANK_ROLE_SEED is the union of them all, not any one
29
29
  // file. Read in filename order; every file is scanned for `SELECT '<role>', unnest(…)`
30
30
  // blocks, so a new grant migration needs no change here.
31
+ // SCHEMA migrations — they shape the tables, they do not grant. Excluded by NAME
32
+ // rather than by "does it INSERT?" so that `a grant migration must INSERT something`
33
+ // below stays a real assertion: a file we believe grants but which inserts nothing is
34
+ // a bug worth failing on, and a content-sniffing filter would quietly excuse it.
35
+ const SCHEMA_MIGRATIONS = new Set([
36
+ 'governance_001_tables.sql', // creates the three tables
37
+ 'government_001_rename_from_governance.sql', // ADR 0174 rename (task 1003004)
38
+ ]);
31
39
  const grantMigrationFiles = fs.readdirSync(MIG_DIR)
32
- .filter((f) => f.endsWith('.sql') && f !== 'governance_001_tables.sql')
40
+ .filter((f) => f.endsWith('.sql') && !SCHEMA_MIGRATIONS.has(f))
33
41
  .sort();
34
42
  const grantSqlByFile = grantMigrationFiles.map((f) => [f, fs.readFileSync(path.join(MIG_DIR, f), 'utf8')]);
35
43
 
@@ -38,7 +38,7 @@ import { fileURLToPath } from 'node:url';
38
38
 
39
39
  const require = createRequire(import.meta.url);
40
40
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
41
- const GOV = path.join(ROOT, 'modules', 'governance');
41
+ const GOV = path.join(ROOT, 'modules', 'government');
42
42
 
43
43
  // auth.js destructures lookupSession at load, so the stub must be installed before
44
44
  // ANYTHING pulls auth.js in (src/module-api does, via the governance route file).
@@ -1,7 +1,7 @@
1
1
  // tests/governance_vanilla_boot.mjs — the VANILLA BOOT proof (BV1.R102, ADR 0151).
2
2
  //
3
3
  // The core/host split only holds if a FRESH instance — one that has never been
4
- // branded, with no config/governance.json on disk and no rows in
4
+ // branded, with no config/government.json on disk and no rows in
5
5
  // governance_builder_roles — comes up sane, anonymous, and powerless. This file is
6
6
  // that proof. It is deliberately scoped to what R96's tests/governance_config.mjs
7
7
  // does NOT cover: that file pins the config CONTRACT (precedence, per-field merge,
@@ -37,7 +37,7 @@ import { fileURLToPath } from 'node:url';
37
37
 
38
38
  const require = createRequire(import.meta.url);
39
39
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
40
- const GOV = path.join(ROOT, 'modules', 'governance');
40
+ const GOV = path.join(ROOT, 'modules', 'government');
41
41
  const catalog = require(path.join(GOV, 'catalog.js'));
42
42
  const { loadGovernanceConfig, resolveGovernanceConfig, NEUTRAL_PATH, INSTANCE_PATH } = require(path.join(GOV, 'config.js'));
43
43
  const { effectivePermissions, resolveBuilderPermissions } = require(path.join(GOV, 'resolver.js'));
@@ -127,10 +127,10 @@ test('the identity guard is not a no-op — a planted host brand in the neutral
127
127
  // trip it, in the exact file this task is about.
128
128
  for (const brand of ['Off the Boats', 'amazonprimea.com']) {
129
129
  const poisoned = NEUTRAL_TEXT.replace('"roles"', `"instance": "${brand}",\n "roles"`);
130
- const found = fitness.scanPromptIdentity('config/governance.neutral.json', poisoned, '.json');
130
+ const found = fitness.scanPromptIdentity('config/government.neutral.json', poisoned, '.json');
131
131
  assert.ok(found.length >= 1, `a "${brand}" literal in the neutral pack must be caught`);
132
132
  }
133
- assert.deepEqual(fitness.scanPromptIdentity('config/governance.neutral.json', NEUTRAL_TEXT, '.json'), [], 'the real pack is clean');
133
+ assert.deepEqual(fitness.scanPromptIdentity('config/government.neutral.json', NEUTRAL_TEXT, '.json'), [], 'the real pack is clean');
134
134
  });
135
135
 
136
136
  // ── (c) the trust boundary on a vanilla boot ────────────────────────────────────
@@ -32,7 +32,7 @@ const SRC = fs.readFileSync(path.join(ROOT, 'src/bongos/serve-internal.js'), 'ut
32
32
  // correct for the genuinely public pages and a BUG anywhere else, so every such
33
33
  // row is spelled out rather than left to a default.
34
34
  //
35
- // Audiences (the floors live in modules/governance/catalog.js; the gate
35
+ // Audiences (the floors live in modules/government/catalog.js; the gate
36
36
  // functions in src/bongos/auth.js):
37
37
  // requireBuilderPage page.view.public any signed-in builder (xenos+)
38
38
  // requireGovernancePage page.view.governance metic+ (ADR 0157)
@@ -336,8 +336,8 @@ app.use(attachFail);
336
336
  // currently impersonating, so the cases below exercise the PERMISSION decision rather
337
337
  // than the port-missing fallback.
338
338
  const seams = require('../src/module-seams.js');
339
- const catalog = require('../modules/governance/catalog.js');
340
- seams.registerProvider('governance', {
339
+ const catalog = require('../modules/government/catalog.js');
340
+ seams.registerProvider('government', {
341
341
  resolveBuilderPermissions: async () => catalog.seedForRank(
342
342
  (fixture.session && fixture.session.rank) || 'xenos',
343
343
  ),
@@ -197,7 +197,7 @@ test('the live tree discovers the extracted modules cleanly (BV1.R43/R48/R47/R49
197
197
  // That is precisely how the agents regression reached an open PR (task 1002485).
198
198
  loader._reset();
199
199
  const snap = loader.loaderSnapshot();
200
- assert.deepEqual(snap.loaded, ['agents', 'autonomy', 'builder-settings', 'dev-box', 'discord', 'economy', 'governance', 'grading', 'hall-ui', 'ideas', 'lifecycle', 'memory', 'onboarding', 'platform-identity', 'provisioning', 'security', 'sessions', 'status-ui']);
200
+ assert.deepEqual(snap.loaded, ['agents', 'autonomy', 'builder-settings', 'dev-box', 'discord', 'economy', 'government', 'grading', 'hall-ui', 'ideas', 'lifecycle', 'memory', 'onboarding', 'platform-identity', 'provisioning', 'security', 'sessions', 'status-ui']);
201
201
  assert.deepEqual(snap.errors, []);
202
202
  assert.deepEqual(snap.skipped, []);
203
203
  loader._reset();
@@ -43,8 +43,8 @@ async function t(name, fn) {
43
43
  // src/bongos/routes, so we patch the resolved module before requiring the
44
44
  // routes.
45
45
  const authPath = require.resolve('../src/bongos/auth.js');
46
- const catalog = require('../modules/governance/catalog.js');
47
- // Mirrors the canonical ladder in modules/governance/catalog.js — omitting a rung
46
+ const catalog = require('../modules/government/catalog.js');
47
+ // Mirrors the canonical ladder in modules/government/catalog.js — omitting a rung
48
48
  // would resolve its floor to Infinity and deny everyone, including archon. Kept at
49
49
  // module scope (BV1.R104) so requireRank and requirePermission below share ONE
50
50
  // ladder; R105's branch still had the stale 3-rung inline copy that dropped thetes.
@@ -40,7 +40,7 @@ const rrc = require(path.join(ROOT, 'src', 'bongos', 'route-rank-check.js'));
40
40
  const sequence = require(path.join(ROOT, 'scripts', 'gds', 'sequence.js'));
41
41
  const boxConnect = require(path.join(ROOT, 'scripts', 'gds', 'box-connect-lib.js'));
42
42
  const boxes = require(path.join(ROOT, 'modules', 'dev-box', 'boxes.js'));
43
- const catalog = require(path.join(ROOT, 'modules', 'governance', 'catalog.js'));
43
+ const catalog = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
44
44
 
45
45
  const LADDER = kernel.LIVE_RANK_LADDER;
46
46
  const TIER = kernel.RANK_TIER;
@@ -142,7 +142,7 @@ const MAP_ALLOWLIST = new Set([
142
142
  // Where a rank-ladder array literal is allowed to exist.
143
143
  const LADDER_ALLOWLIST = new Set([
144
144
  'src/bongos/db-kernel.js', // the canonical source itself
145
- 'modules/governance/catalog.js',
145
+ 'modules/government/catalog.js',
146
146
  'src/bongos/route-rank-check.js',
147
147
  ...STATIC_LADDER_FILES,
148
148
  ]);
@@ -9,7 +9,7 @@
9
9
  // a downgrade that reads as legitimate, and a published API doc that misstates authority.
10
10
  //
11
11
  // THE ORACLE PROBLEM (the trap R103 fell into). The classifier DERIVES a permission's
12
- // rank from modules/governance/catalog.js, so asserting it back against catalog.floor
12
+ // rank from modules/government/catalog.js, so asserting it back against catalog.floor
13
13
  // would move both sides together and prove nothing. Every expectation below is therefore
14
14
  // either a HAND-WRITTEN literal (a floor read off the catalog once, by a human, and
15
15
  // frozen here — so a floor edit reds this file and has to be argued with) or
@@ -67,7 +67,7 @@ const HAND_WRITTEN_FLOORS = {
67
67
  // oracle, not a tautology.
68
68
 
69
69
  test('P0: the parsed floor map matches the catalog module exactly (key set and floors)', () => {
70
- const catalog = require(path.join(ROOT, 'modules', 'governance', 'catalog.js'));
70
+ const catalog = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
71
71
  const parsed = rrc.permissionFloors();
72
72
  const evaluated = new Map(catalog.PERMISSIONS.map((p) => [p.key, p.floor]));
73
73
  assert.equal(parsed.size, evaluated.size,
@@ -1,11 +0,0 @@
1
- {
2
- "key": "governance",
3
- "title": "Governance (configurable roles & permissions)",
4
- "description": "Discord-style configurable roles and permissions (ADR 0151, BONGOS-V1 goal 1000030). Permissions are the atomic authority unit and the four ranks (xenos/thetes/metic/archon) become seeded roles; this module owns the code-defined permission catalog (each key flagged `system` = trust-boundary, non-grantable, or operational = delegable) plus the compatibility seed that reproduces today's rank thresholds exactly. A core-domain module, default-on: a Cloud Bongos instance ships configurable roles the way it ships its status page. This first slice (BV1.R94) is the catalog + seed as code constants — the single source the resolver (R95), the requirePermission gate (R97), and the Archon tab (R110/R111) all read. Preserves ADR 0016 (authority resolved server-side, per request, uncached).",
5
- "coreVersion": "^1.18.0",
6
- "default": true,
7
- "maintenance": { "status": "core-maintained" },
8
- "contributes": { "migrations": true, "routes": ["governance", "role-sync"] },
9
- "provides": ["governance", "governance.roleSync"],
10
- "consumes": []
11
- }
File without changes
File without changes