@bongos/core 1.19.838 → 1.19.839

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.838",
6
- "core_contract": "1.19.838",
7
- "source_commit": "f5c78584166eedac7972dcb10f61e55d7c1685e7",
5
+ "core_version": "1.19.839",
6
+ "core_contract": "1.19.839",
7
+ "source_commit": "2799589e44782acf35629e14f332ac30686ed028",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-17T17:02:39.487Z",
9
+ "built_at": "2026-09-17T17:25:32.211Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 494,
13
13
  "agent_docs_stubbed": 26,
14
- "functional_verbatim": 2257,
14
+ "functional_verbatim": 2258,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2777,
20
- "tree_sha256": "61bef3a77f3f90a904e83ae13d78fa314c21c944451e91a369fb047fc78d9b7a",
19
+ "file_count": 2778,
20
+ "tree_sha256": "209c682e3b1a302720d23b8e207501aba43d917dc24ebe0fe4d11836c49a6af8",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -382,7 +382,7 @@
382
382
  {
383
383
  "path": "config/branding.neutral.json",
384
384
  "mode": "0000644",
385
- "sha256": "b56024a95ccf9e236bf8248b7d1f96c4510e3feac55c2885497ecd8f841bdb7b"
385
+ "sha256": "3c46f007c474b0fe300ad1c6e2c80237948a81a8ad726f15f74ec5ba7cf2b610"
386
386
  },
387
387
  {
388
388
  "path": "config/design-tokens.neutral.json",
@@ -2022,12 +2022,12 @@
2022
2022
  {
2023
2023
  "path": "docs/branding-contract.md",
2024
2024
  "mode": "0000644",
2025
- "sha256": "807e79e99b60a7a310c532af8ce5d3c9a23da4f5ac568cf6dd501feeca93ba46"
2025
+ "sha256": "78cb92eedefb10a2cd23b0dff8e2a6d5499295487372b7ef7da5619f99d4cdde"
2026
2026
  },
2027
2027
  {
2028
2028
  "path": "docs/branding-fill-prompt.md",
2029
2029
  "mode": "0000644",
2030
- "sha256": "38961b4a3b3e0789b64365dc3cb70eb3407f45e9a8ecdd1667ef80ec8470e272"
2030
+ "sha256": "91e0fab10096223b9e99ba764330b61f5c64f754d0b2845a050057ddbe5a34e0"
2031
2031
  },
2032
2032
  {
2033
2033
  "path": "docs/canonical-permissions.md",
@@ -2037,12 +2037,12 @@
2037
2037
  {
2038
2038
  "path": "docs/copy-inventory.md",
2039
2039
  "mode": "0000644",
2040
- "sha256": "47070b89dd6a26d425e630db6b592b9b99ce73197e39c21b416caa5a12b330df"
2040
+ "sha256": "e457040f6938ad12012fb8ceb1b59de65d43f2fca74849181f1e448979a4c811"
2041
2041
  },
2042
2042
  {
2043
2043
  "path": "docs/copy-registry.json",
2044
2044
  "mode": "0000644",
2045
- "sha256": "cceabb45bbe7b9aabe8484777a8567fc9d73f274486475a80b1c04a43152f7c8"
2045
+ "sha256": "77a0c2bb223c37af27b3dac3ca8864bad9b1bcb0bc6c326c96f40cec6f9ba95d"
2046
2046
  },
2047
2047
  {
2048
2048
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2567,7 +2567,7 @@
2567
2567
  {
2568
2568
  "path": "docs/module-api-changelog.md",
2569
2569
  "mode": "0000644",
2570
- "sha256": "aed7cd21803eab964c3d296c5f938e8c94b9e05fb865ce3bb5780574a5fdcebb"
2570
+ "sha256": "689361320ab6192aade8cb602c862af1f14454238575da829015077f55743628"
2571
2571
  },
2572
2572
  {
2573
2573
  "path": "docs/modules-contract.md",
@@ -7432,7 +7432,7 @@
7432
7432
  {
7433
7433
  "path": "modules/status-ui/public/index.html",
7434
7434
  "mode": "0000644",
7435
- "sha256": "c9a37a51e098cd7ab7dfbb1a800b767ac25f5ade6ef40c22ea47ca326a4b8dc3"
7435
+ "sha256": "25e98c2822bb8b3613edbe369ac374128e07bc6c8abf126f90a781e5e0238e8e"
7436
7436
  },
7437
7437
  {
7438
7438
  "path": "modules/status-ui/public/snapshots/.gitkeep",
@@ -7867,12 +7867,12 @@
7867
7867
  {
7868
7868
  "path": "package-lock.json",
7869
7869
  "mode": "0000644",
7870
- "sha256": "9baa1aa306e1c7925d66fc09484dc2c214ad13fa47e4d71c39fc6d7ca2d6e8a6"
7870
+ "sha256": "fe22ff711989f39c34fa95045c0736e26abc2400d698548f353121fbd1ff8828"
7871
7871
  },
7872
7872
  {
7873
7873
  "path": "package.json",
7874
7874
  "mode": "0000644",
7875
- "sha256": "9b0fe6c23bdb7eb915bcb6d049e341258d1daa654a791355ac8ca92bfd58a02b"
7875
+ "sha256": "f15fdfca04599ce879e85f8229aeba9019d17476e6020ebdec4ea03a98d4bd76"
7876
7876
  },
7877
7877
  {
7878
7878
  "path": "public-docs/index.html",
@@ -8372,7 +8372,7 @@
8372
8372
  {
8373
8373
  "path": "scripts/gds/fitness-checks-identity.js",
8374
8374
  "mode": "0000644",
8375
- "sha256": "583b21bf6527b657058ebfab50aff8c51cec96a0b1baa4d01daea55e90d0ccf7"
8375
+ "sha256": "ae5589886edaa98d66d7bb4b918b47220628c82337535ffeaa2b5cb0c5e2adc0"
8376
8376
  },
8377
8377
  {
8378
8378
  "path": "scripts/gds/fitness-checks-packaging.js",
@@ -8412,7 +8412,7 @@
8412
8412
  {
8413
8413
  "path": "scripts/gds/fitness.js",
8414
8414
  "mode": "0000644",
8415
- "sha256": "42c49bcab43be3367f05b99f4dfded590edf89ae10c1a3df2d9312b6e0d33fc9"
8415
+ "sha256": "5f96e59cb4c27e20c6acaabf8f97b94dc69875b5fb5770fb37e4fb838128b189"
8416
8416
  },
8417
8417
  {
8418
8418
  "path": "scripts/gds/gate-review.js",
@@ -9457,7 +9457,7 @@
9457
9457
  {
9458
9458
  "path": "scripts/status-mirror-sync.js",
9459
9459
  "mode": "0000644",
9460
- "sha256": "845c8dad87038fe273563e8eda7126e70ac1afe8f9eee8c4364a4404490c4f5f"
9460
+ "sha256": "013860b6269302ca2b9db511cfdd3b915e9963bfcbd3d528dcd086cbe40f94a8"
9461
9461
  },
9462
9462
  {
9463
9463
  "path": "scripts/status-probe.mjs",
@@ -9772,7 +9772,7 @@
9772
9772
  {
9773
9773
  "path": "src/bongos/serve-internal.js",
9774
9774
  "mode": "0000644",
9775
- "sha256": "697273b43a6825da4828c7b9e6e721843dcf9fd74bd30b94cc22e129995110f4"
9775
+ "sha256": "fb6c9149b602356e3973b62c5042c373c92018e04242decd4a29c2c0897ddec3"
9776
9776
  },
9777
9777
  {
9778
9778
  "path": "src/bongos/uptime-poller.js",
@@ -9782,7 +9782,7 @@
9782
9782
  {
9783
9783
  "path": "src/branding.js",
9784
9784
  "mode": "0000644",
9785
- "sha256": "1d9d566c08fcba34060177bf1bd9c47df08f7c61b6805c305a34fd2d0d280310"
9785
+ "sha256": "086e80cd5effd41bcbada467b5538afa2d35f549b8efd90408d99e39ab2e29ec"
9786
9786
  },
9787
9787
  {
9788
9788
  "path": "src/build-info.js",
@@ -9802,7 +9802,7 @@
9802
9802
  {
9803
9803
  "path": "src/module-api.js",
9804
9804
  "mode": "0000644",
9805
- "sha256": "3363fefd57cbb3a31327b1c613ebdd4a325e26071a575237a7e0ec467a3f74c7"
9805
+ "sha256": "027988bab5433e279e5b5cd479a768f655dd68bc1e7e19d31279d140be462d2a"
9806
9806
  },
9807
9807
  {
9808
9808
  "path": "src/module-loader/catalog.js",
@@ -11032,7 +11032,7 @@
11032
11032
  {
11033
11033
  "path": "tests/fitness.mjs",
11034
11034
  "mode": "0000644",
11035
- "sha256": "b222f8b2436ccf9f392c836104e9f889a8bbe537390fcd53872f359114388f0a"
11035
+ "sha256": "7252f8134ae29b16df7c136865acb110263cc862781d7ae26ee416398caa1f09"
11036
11036
  },
11037
11037
  {
11038
11038
  "path": "tests/fitness_gds_ratchet.mjs",
@@ -13509,6 +13509,11 @@
13509
13509
  "mode": "0000644",
13510
13510
  "sha256": "369981934c65608fb4198c7840bd918c25caa3e5a1aa44b22fe38663e728e7f2"
13511
13511
  },
13512
+ {
13513
+ "path": "tests/status_company_attribution.mjs",
13514
+ "mode": "0000644",
13515
+ "sha256": "4b92c96ae496736b0f44182e64d42a24f108cb51fbeb5cf7cd5814ad336b14f6"
13516
+ },
13512
13517
  {
13513
13518
  "path": "tests/status_mirror_sync.mjs",
13514
13519
  "mode": "0000644",
@@ -5,7 +5,8 @@
5
5
  "worldName": "Cloud Bongos",
6
6
  "company": {
7
7
  "name": "",
8
- "site": ""
8
+ "site": "",
9
+ "tagline": ""
9
10
  }
10
11
  },
11
12
  "llmProjectName": "this project",
@@ -21,7 +21,7 @@ env override → instance config (config/branding.json) → neutral star
21
21
  |---|---|
22
22
  | `identity.productName` | The product name (e.g. "Example"). **Required.** |
23
23
  | `identity.worldName` | The in-world / civilization name rendered at runtime (e.g. "Example"). **Required.** |
24
- | `identity.company` | `{ name, site }` of the operating company (may be empty). |
24
+ | `identity.company` | `{ name, site, tagline }` of the operating company — every field may be empty. `tagline` is the free-text clause that follows the name in the status page footer ("{{worldName}} is the work of **name**, *tagline*."), so put a location there if you want one; there is no separate location field. The footer stamps them as `{{companyName}}` / `{{companySite}}` / `{{companyTagline}}`, and each clause sits in a `<!--brand-if:KEY-->…<!--/brand-if:KEY-->` region that drops whole when its field is empty: no name hides the whole sentence, no site renders the name unlinked, no tagline ends the sentence at the name. (task [#1002853](https://cloudbongos.com/builders#/task/1002853)) |
25
25
  | `llmProjectName` | The project name injected into grader / architect / onboarding **LLM prompts**, so a non-OTB instance is graded against its own identity. **Required.** |
26
26
  | `domains.publicOrigin` | Public game/app origin. **Required.** |
27
27
  | `domains.buildersOrigin` / `statusOrigin` | Hall + status origins. **These three (`publicOrigin`/`buildersOrigin`/`statusOrigin`) are the docs-discovery contract** ([ADR 0114](adr/0114-instance-docs-discovery-contract.md)): the hall is the canonical doc-reading surface, `/docs` on `publicOrigin` renders the API reference, the status page is the outage fallback. `GET <publicOrigin>/api/bongos` re-advertises them (`hall`/`status`/`public`) so an agent resolves the surfaces with no hard-coded host. |
@@ -8,7 +8,7 @@ Paste the block below into your own LLM (Claude, etc.). It interviews you and em
8
8
  >
9
9
  > Interview me for:
10
10
  > 1. **Product name** and the **in-world / display name** (can be the same).
11
- > 2. **Operating company** name + website (optional).
11
+ > 2. **Operating company** name + website + a one-line descriptor such as "a rocket works in Dayton, Ohio" (all optional; `identity.company.tagline`).
12
12
  > 3. **Domains:** public origin, hall origin, status origin, the OAuth sign-in origin, and the session cookie domain (use `""` for a host-only cookie unless you run subdomains — never widen it casually).
13
13
  > 4. **GitHub repo** (`owner`, `name`) this instance ships to.
14
14
  > 5. **Reward currency label** (the unit builders earn; the math is fixed — this is display only).
@@ -1472,7 +1472,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
1472
1472
  | id | conf | text | where |
1473
1473
  |---|---|---|---|
1474
1474
  | `33aaf5eb47b2` | certain | ${…} of ${…} spent | `modules/status-ui/public/status.js:222` |
1475
- | `c5fbe5ea4335` | certain | , a third-party logistics house in Cleveland, Ohio. | `modules/status-ui/public/index.html:355` |
1475
+ | `d31b6094f7ac` | certain | , {{companyTagline}} | `modules/status-ui/public/index.html:356` |
1476
1476
  | `2045078fb115` | certain | 90 days ago | `modules/status-ui/public/status.js:477` |
1477
1477
  | `e4848e2d9386` | certain | A new portrait is set down each time the city's stones are reshaped. Scroll to see how {{worldName}} has grown | `modules/status-ui/public/index.html:344` |
1478
1478
  | `390faeaffb47` | certain | A project | `modules/status-ui/public/explore.js:71` |
@@ -1560,10 +1560,10 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
1560
1560
  | `b97f429c33fe` | certain | works shipped (90d) | `modules/status-ui/public/index.html:218` |
1561
1561
  | `71a303e1ba09` | certain | works wrought, last 7 days | `modules/status-ui/public/index.html:167` |
1562
1562
  | `24ea04f49b3d` | certain | year's purse | `modules/status-ui/public/index.html:259` |
1563
- | `4c45bbf03088` | certain | {{Currency}} are wrought by the lawmen's review; redemption awaits their seal. | `modules/status-ui/public/index.html:356` |
1563
+ | `4c45bbf03088` | certain | {{Currency}} are wrought by the lawmen's review; redemption awaits their seal. | `modules/status-ui/public/index.html:357` |
1564
1564
  | `89aa84ef4595` | certain | {{Currency}} spent, against the value wrought. | `modules/status-ui/public/index.html:245` |
1565
1565
  | `35872b9ecc49` | certain | {{currency}} spent | `modules/status-ui/public/index.html:251` |
1566
- | `e87f28d25342` | certain | {{worldName}} is the work of | `modules/status-ui/public/index.html:355` |
1566
+ | `e87f28d25342` | certain | {{worldName}} is the work of | `modules/status-ui/public/index.html:356` |
1567
1567
  | `7a15e19adbd2` | certain | {{worldName}} — the public ledger | `modules/status-ui/public/index.html:6` |
1568
1568
  | `7a15e19adbd2` | certain | {{worldName}} — the public ledger | `modules/status-ui/public/index.html:6` |
1569
1569
  | `12e0efd49a32` | certain | {…} goal{…} · {…} achieved | `modules/status-ui/public/status.js:582` |
@@ -17802,11 +17802,11 @@
17802
17802
  "confidence": "certain"
17803
17803
  },
17804
17804
  {
17805
- "id": "c5fbe5ea4335",
17805
+ "id": "d31b6094f7ac",
17806
17806
  "surface": "status-dashboard",
17807
- "text": ", a third-party logistics house in Cleveland, Ohio.",
17807
+ "text": ", {{companyTagline}}",
17808
17808
  "file": "modules/status-ui/public/index.html",
17809
- "line": 355,
17809
+ "line": 356,
17810
17810
  "origin": "html-text",
17811
17811
  "confidence": "certain"
17812
17812
  },
@@ -18598,7 +18598,7 @@
18598
18598
  "surface": "status-dashboard",
18599
18599
  "text": "{{Currency}} are wrought by the lawmen's review; redemption awaits their seal.",
18600
18600
  "file": "modules/status-ui/public/index.html",
18601
- "line": 356,
18601
+ "line": 357,
18602
18602
  "origin": "html-text",
18603
18603
  "confidence": "certain"
18604
18604
  },
@@ -18625,7 +18625,7 @@
18625
18625
  "surface": "status-dashboard",
18626
18626
  "text": "{{worldName}} is the work of",
18627
18627
  "file": "modules/status-ui/public/index.html",
18628
- "line": 355,
18628
+ "line": 356,
18629
18629
  "origin": "html-text",
18630
18630
  "confidence": "certain"
18631
18631
  },
@@ -2150,5 +2150,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2150
2150
  landed since 1.19.836 with no explicit bump. run 35248928789. (task 1002620)
2151
2151
  1.19.838 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2152
2152
  landed since 1.19.837 with no explicit bump. run 35250225228. (task 1002620)
2153
+ 1.19.839 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2154
+ landed since 1.19.838 with no explicit bump. run 35252591179. (task 1002620)
2153
2155
  ---------------------------------------------------------------------------
2154
2156
  ```
@@ -352,7 +352,8 @@
352
352
  <svg><use href="#orn-diamond"/></svg>
353
353
  </div>
354
354
  <p class="foot__seal">By order of the Senate</p>
355
- <p>{{worldName}} is the work of <a href="https://hermeslines.com" target="_blank" rel="noopener"><strong>Hermeslines</strong></a>, a third-party logistics house in Cleveland, Ohio.</p>
355
+ <!-- task 1002853: every company field is optional, so each clause drops whole when its pack field is empty -->
356
+ <!--brand-if:companyName--><p>{{worldName}} is the work of <!--brand-if:companySite--><a href="{{companySite}}" target="_blank" rel="noopener"><!--/brand-if:companySite--><strong>{{companyName}}</strong><!--brand-if:companySite--></a><!--/brand-if:companySite--><!--brand-if:companyTagline-->, {{companyTagline}}<!--/brand-if:companyTagline-->.</p><!--/brand-if:companyName-->
356
357
  <p>{{Currency}} are wrought by the lawmen's review; redemption awaits their seal.</p>
357
358
  </footer>
358
359
 
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.838",
3
+ "version": "1.19.839",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.838",
9
+ "version": "1.19.839",
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.838",
3
+ "version": "1.19.839",
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",
@@ -41,6 +41,9 @@ const { CORE_ROOT, MODULE_ROOTS, REPO_ROOT, rel } = require('./fitness-lib.js');
41
41
  const PROMPT_IDENTITY_LITERALS = [
42
42
  /off the boats/i,
43
43
  /amazonprimea/i,
44
+ // The host's operating company (task 1002853): the scan already covered the status
45
+ // page's HTML, but with only the product listed its footer credited this company for years.
46
+ /hermeslines/i,
44
47
  ];
45
48
  // Scan roots (recursive) + kernel-prompt CLIs that live outside them.
46
49
  // scripts/gds joined at task 1002427: the builder CLI was UNSCANNED, which is how
@@ -101,7 +104,7 @@ const IDENTITY_SCAN_EXTRA_FILES = [];
101
104
  const IDENTITY_SCAN_ALLOWED = {
102
105
  // task 1003206 moved Check 13's own regexes out of fitness.js into THIS file
103
106
  // when the monolith was split, so the detector's self-carve-out moved with them.
104
- 'scripts/gds/fitness-checks-identity.js': 2,
107
+ 'scripts/gds/fitness-checks-identity.js': 3,
105
108
  'scripts/gds/package-core.js': 1,
106
109
  // audit-replay.sh + db-backup-{nightly,offsite}.sh were carved out here as
107
110
  // "host-pinned ops"; task 1002757 RETIRED that justification for them — each
@@ -125,6 +128,11 @@ const IDENTITY_SCAN_ALLOWED = {
125
128
  'scripts/gds/seed-productization-tasks.js': 6,
126
129
  'scripts/gds/seed-provisioning-tasks.js': 2,
127
130
  'scripts/gds/version-close.js': 1,
131
+ // task 1002853 (the company literal joined the list): audit-authorship.sh is itself a
132
+ // detector — its ops allowlist names the founder's commit address so it can exempt it; grade-smoke.js
133
+ // is a protected grader probe whose fixture task prose names the company, the seed-*.js rationale.
134
+ 'scripts/gds/audit-authorship.sh': 1,
135
+ 'scripts/gds/grade-smoke.js': 1,
128
136
  };
129
137
  // `.sh` joined at task 1002567: the extension set was `.js/.html/.css`, so NO shell
130
138
  // script had ever been scanned — which is how scripts/gds/lib.sh kept a hardcoded
@@ -113,6 +113,12 @@ const ROOT_CHAR_HARD_MAX = 42000; // ~10.5K tokens — the always-loaded file mu
113
113
  const ROOT_CHAR_TARGET = 32000; // ~8K tokens — aspirational, mirrors the ~200-line aim.
114
114
  const estTokens = (n) => Math.round(n / 4); // ~4 chars/token for markdown prose.
115
115
 
116
+ // Where the charter BODY lives since task 1003687. It is guidance for EDITING a
117
+ // CLAUDE.md, so it is paths-scoped (`paths:` frontmatter, same mechanism as
118
+ // .claude/rules/hook-authoring.md) and costs nothing in the sessions — the large
119
+ // majority — that never open one. The kernel keeps the heading and a pointer.
120
+ const CHARTER_RULE_REL = '.claude/rules/claudemd-authoring.md';
121
+
116
122
  function checkClaudeMdBudget(opts = {}) {
117
123
  const p = path.join(INSTANCE_ROOT, 'CLAUDE.md'); // the root CLAUDE.md is INSTANCE content (materialized per instance; ADR 0108)
118
124
  const text = opts.text != null ? opts.text : fs.readFileSync(p, 'utf8');
@@ -133,8 +139,35 @@ function checkClaudeMdBudget(opts = {}) {
133
139
  }
134
140
  if (!text.includes('## Working with this file (content charter)')) {
135
141
  violations.push('CLAUDE.md is missing the content-charter section (ADR 0061) — the per-line test + "what goes where" table must stay.');
142
+ } else {
143
+ // Task 1003687 relocated the charter BODY to a paths-scoped rule, so the kernel
144
+ // keeps the heading and a pointer. That makes the heading cheap to fake: a section
145
+ // with nothing behind it satisfies a substring check while the rules it names are
146
+ // gone. So the charter must resolve to something — either inline here, or through a
147
+ // pointer whose target actually exists and still carries the two rules + the table.
148
+ const namesRule = text.includes(CHARTER_RULE_REL);
149
+ const inlineCharter = text.includes('Per-line test:');
150
+ if (namesRule) {
151
+ const rulePath = path.join(INSTANCE_ROOT, CHARTER_RULE_REL); // .claude/ is materialized INSTANCE content (ADR 0108 §3)
152
+ if (!fs.existsSync(rulePath)) {
153
+ violations.push(`CLAUDE.md points its content charter at ${CHARTER_RULE_REL}, but that file does not exist — a pointer to nothing is worse than no pointer (ADR 0061 / task 1003687).`);
154
+ } else {
155
+ const rule = fs.readFileSync(rulePath, 'utf8');
156
+ const missing = [];
157
+ if (!/^---\r?\n[\s\S]*?\bpaths:[\s\S]*?["']\*\*\/CLAUDE\.md["'][\s\S]*?^---$/m.test(rule)) {
158
+ missing.push('`paths:` frontmatter matching `**/CLAUDE.md` (without it the rule never loads, and the charter is simply gone)');
159
+ }
160
+ if (!rule.includes('Per-line test:')) missing.push('the per-line test');
161
+ if (!rule.includes('## What goes where')) missing.push('the "what goes where" table');
162
+ if (missing.length) {
163
+ violations.push(`${CHARTER_RULE_REL} is missing ${missing.join(', ')} — the kernel delegates the charter to it, so the charter is only as real as that file (ADR 0061 / task 1003687).`);
164
+ }
165
+ }
166
+ } else if (!inlineCharter) {
167
+ violations.push('The CLAUDE.md content-charter section is hollow — it has the heading but neither the per-line test inline nor a pointer to `' + CHARTER_RULE_REL + '`. The heading exists to make the rules findable; on its own it only satisfies this check (ADR 0061).');
168
+ }
136
169
  }
137
- return { name: 'root CLAUDE.md budget + charter', ok: violations.length === 0, hardFail: violations.length > 0, violations, warnings, note: `≤ ${ROOT_HARD_MAX} lines / ${ROOT_CHAR_HARD_MAX} chars (~${estTokens(ROOT_CHAR_HARD_MAX)} tok); targets ~${ROOT_TARGET} lines / ~${estTokens(ROOT_CHAR_TARGET)} tok; charter present.` };
170
+ return { name: 'root CLAUDE.md budget + charter', ok: violations.length === 0, hardFail: violations.length > 0, violations, warnings, note: `≤ ${ROOT_HARD_MAX} lines / ${ROOT_CHAR_HARD_MAX} chars (~${estTokens(ROOT_CHAR_HARD_MAX)} tok); targets ~${ROOT_TARGET} lines / ~${estTokens(ROOT_CHAR_TARGET)} tok; charter resolves (inline or via ${CHARTER_RULE_REL}).` };
138
171
  }
139
172
 
140
173
  // ============================================================================
@@ -48,7 +48,7 @@ const { execFileSync } = require('node:child_process');
48
48
 
49
49
  const REPO_ROOT = path.resolve(__dirname, '..');
50
50
  const SRC = path.join(REPO_ROOT, 'modules', 'status-ui', 'public');
51
- const { branding, clientBranding } = require('../src/branding');
51
+ const { branding, clientBranding, applyBrandConditionals } = require('../src/branding');
52
52
 
53
53
  // Stamp instance-identity tokens into the mirror HTML. The off-box mirror is
54
54
  // served by a static Pages host, NOT the branding-injecting Node server — so this
@@ -63,15 +63,19 @@ function brandTokens(html, brand = {}, publicOrigin = '', buildersOrigin = '') {
63
63
  const tagline = (brand.copy && brand.copy.tagline) || '';
64
64
  const cur = (brand.currency && brand.currency.label) || 'credits';
65
65
  const Cur = cur ? cur.charAt(0).toUpperCase() + cur.slice(1) : cur;
66
+ const company = (brand.identity && brand.identity.company) || {};
66
67
  const esc = (s) => String(s == null ? '' : s)
67
68
  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
68
69
  .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
69
- return html
70
+ return applyBrandConditionals(html, { companyName: company.name, companySite: company.site, companyTagline: company.tagline })
70
71
  .split('{{worldName}}').join(esc(world))
71
72
  .split('{{productName}}').join(esc(product))
72
73
  .split('{{Currency}}').join(esc(Cur))
73
74
  .split('{{currency}}').join(esc(cur))
74
75
  .split('{{tagline}}').join(esc(tagline))
76
+ .split('{{companyName}}').join(esc(company.name))
77
+ .split('{{companySite}}').join(esc(company.site))
78
+ .split('{{companyTagline}}').join(esc(company.tagline))
75
79
  .split('{{publicOrigin}}').join(esc(publicOrigin || ''))
76
80
  .split('{{buildersOrigin}}').join(esc(buildersOrigin || publicOrigin || ''));
77
81
  }
@@ -46,7 +46,7 @@ const { buildStampedHtml } = require('../asset-version');
46
46
  const { buildInfo } = require('../build-info');
47
47
  const { buildDevboxDownloads } = require('../devbox-downloads');
48
48
  const { buildBongosDownloads } = require('../bongos-downloads');
49
- const { clientBranding, branding } = require('../branding');
49
+ const { clientBranding, branding, applyBrandConditionals } = require('../branding');
50
50
  const { prelaunchGate } = require('./prelaunch-gate');
51
51
  const { platformVisibilityGate } = require('./platform-visibility-gate');
52
52
  const { clientModules, isModuleEnabled } = require('../modules');
@@ -205,6 +205,8 @@ function injectBrandingGlobal(html, brand = clientBranding(), mods = clientModul
205
205
  // served page can carry a correct cross-host href or canonical/og: URL: a client
206
206
  // fill cannot reach them, and a baked one would make every instance advertise
207
207
  // whichever instance happened to author the file (task 1002748, direction C5/C6).
208
+ // {{companyName}} {{companySite}} {{companyTagline}} are optional, so a page wraps
209
+ // each clause in a brand-if region that drops whole when its field is empty (task 1002853).
208
210
  // Pure + exported for the test; both origins are injectable so it drives with zero I/O.
209
211
  function applyBrandTokens(html, brand = clientBranding(), origin = safePublicOrigin(), hallOrigin = safeBuildersOrigin(), sourceRepo = safeSourceRepoUrl(), instanceBase = safeInstanceBase(), hubOrigin = safeHubOrigin()) {
210
212
  const world = (brand.identity && brand.identity.worldName) || '';
@@ -213,12 +215,17 @@ function applyBrandTokens(html, brand = clientBranding(), origin = safePublicOri
213
215
  const cur = (brand.currency && brand.currency.label) || 'credits';
214
216
  const Cur = cur ? cur.charAt(0).toUpperCase() + cur.slice(1) : cur;
215
217
  const hall = hallOrigin || origin || '';
216
- return dropEmptyHrefLinks(String(html == null ? '' : html), { publicOrigin: origin || '', buildersOrigin: hall, sourceRepoUrl: sourceRepo || '' })
218
+ const company = (brand.identity && brand.identity.company) || {};
219
+ const conditioned = applyBrandConditionals(html == null ? '' : html, { companyName: company.name, companySite: company.site, companyTagline: company.tagline });
220
+ return dropEmptyHrefLinks(conditioned, { publicOrigin: origin || '', buildersOrigin: hall, sourceRepoUrl: sourceRepo || '' })
217
221
  .split('{{worldName}}').join(esc(world))
218
222
  .split('{{productName}}').join(esc(product))
219
223
  .split('{{Currency}}').join(esc(Cur))
220
224
  .split('{{currency}}').join(esc(cur))
221
225
  .split('{{tagline}}').join(esc(tagline))
226
+ .split('{{companyName}}').join(esc(company.name))
227
+ .split('{{companySite}}').join(esc(company.site))
228
+ .split('{{companyTagline}}').join(esc(company.tagline))
222
229
  .split('{{publicOrigin}}').join(esc(origin || ''))
223
230
  // a pack that names no hall of its own resolves to its OWN apex — never to
224
231
  // whichever instance authored the file
package/src/branding.js CHANGED
@@ -221,7 +221,11 @@ function clientBranding(b = branding()) {
221
221
  identity: {
222
222
  productName: b.identity?.productName || '',
223
223
  worldName: b.identity?.worldName || '',
224
- company: { name: b.identity?.company?.name || '' },
224
+ company: {
225
+ name: b.identity?.company?.name || '',
226
+ site: b.identity?.company?.site || '',
227
+ tagline: b.identity?.company?.tagline || '',
228
+ },
225
229
  },
226
230
  currency: {
227
231
  label: b.currency?.label || 'credits',
@@ -308,4 +312,20 @@ function clientReward() {
308
312
  }
309
313
  }
310
314
 
311
- module.exports = { resolveBranding, loadBranding, deepMerge, branding, clientBranding, userAgent, NEUTRAL_PATH, INSTANCE_PATH };
315
+ // Resolve the `<!--brand-if:KEY-->…<!--/brand-if:KEY-->` regions of a served page:
316
+ // kept (markers removed) when `values[KEY]` is non-empty, dropped whole otherwise,
317
+ // so an optional pack field removes its entire clause instead of rendering half a
318
+ // sentence (task 1002853). Lives here, not in serve-internal, because the off-box
319
+ // status mirror stamps the same page without loading the server. Repeats until
320
+ // stable so a region nested inside a kept one resolves too.
321
+ const BRAND_IF_REGION = /<!--brand-if:(\w+)-->([\s\S]*?)<!--\/brand-if:\1-->/g;
322
+ function applyBrandConditionals(html, values) {
323
+ let out = String(html);
324
+ for (let prev; prev !== out;) {
325
+ prev = out;
326
+ out = out.replace(BRAND_IF_REGION, (_, key, inner) => (values[key] ? inner : ''));
327
+ }
328
+ return out;
329
+ }
330
+
331
+ module.exports = { resolveBranding, loadBranding, deepMerge, branding, clientBranding, userAgent, applyBrandConditionals, NEUTRAL_PATH, INSTANCE_PATH };
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.838'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.839'; // 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');
package/tests/fitness.mjs CHANGED
@@ -51,6 +51,51 @@ test('CLAUDE.md char/token budget actually fires on within-line bloat (not a no-
51
51
  assert.ok(r.violations.some((v) => /char/i.test(v) && /token/i.test(v)), 'the violation must name the char/token budget');
52
52
  });
53
53
 
54
+ // --- the charter is RELOCATED, not deleted (task 1003687) --------------------
55
+ // The charter body moved to a paths-scoped rule, so the kernel keeps only a heading
56
+ // and a pointer. That makes the heading trivially fakeable: a section with nothing
57
+ // behind it satisfies a substring check while the rules it names are gone. These
58
+ // pin that the check resolves the pointer rather than trusting the heading — a green
59
+ // check over a missing charter would be a false claim of coverage.
60
+ const CHARTER_HEADING = '## Working with this file (content charter)';
61
+ const CHARTER_RULE_REL = '.claude/rules/claudemd-authoring.md';
62
+
63
+ test('the charter rule file exists and is paths-scoped to CLAUDE.md', () => {
64
+ const rule = fs.readFileSync(path.join(ROOT, CHARTER_RULE_REL), 'utf8');
65
+ assert.match(rule, /^---\r?\n[\s\S]*?\bpaths:[\s\S]*?["']\*\*\/CLAUDE\.md["'][\s\S]*?^---$/m,
66
+ 'without `paths:` frontmatter matching **/CLAUDE.md the rule never loads, and the charter is simply gone');
67
+ assert.ok(rule.includes('Per-line test:'), 'the per-line test must survive the move');
68
+ assert.ok(rule.includes('## What goes where'), 'the "what goes where" table must survive the move');
69
+ });
70
+
71
+ test('the live CLAUDE.md delegates the charter to the rule file', () => {
72
+ const kernel = fs.readFileSync(path.join(ROOT, 'CLAUDE.md'), 'utf8');
73
+ assert.ok(kernel.includes(CHARTER_HEADING), 'the heading keeps the rule findable from the file it governs');
74
+ assert.ok(kernel.includes(CHARTER_RULE_REL), 'the heading must point somewhere, or it is decoration');
75
+ });
76
+
77
+ test('a hollow charter heading hard-fails (the heading alone is not the charter)', () => {
78
+ const r = fitness.checkClaudeMdBudget({ text: `${CHARTER_HEADING}\n` });
79
+ assert.equal(r.hardFail, true, 'a heading with neither inline rules nor a pointer must fail');
80
+ assert.ok(r.violations.some((v) => /hollow/i.test(v)), 'the violation must name the hollow section');
81
+ });
82
+
83
+ test('an inline charter still passes (a downstream kernel that never split it)', () => {
84
+ const r = fitness.checkClaudeMdBudget({ text: `${CHARTER_HEADING}\n- **Per-line test:** …\n` });
85
+ assert.equal(r.hardFail, false, 'relocation is the cure, not the requirement — inline is still a real charter');
86
+ });
87
+
88
+ test('a pointer at a missing rule file hard-fails', () => {
89
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'charter-ptr-'));
90
+ fs.writeFileSync(path.join(dir, 'CLAUDE.md'), `${CHARTER_HEADING}\ncharter: ${CHARTER_RULE_REL}\n`);
91
+ const out = require('node:child_process').execFileSync(process.execPath,
92
+ ['-e', `const f=require(${JSON.stringify(path.join(ROOT, 'scripts/gds/fitness.js'))});process.stdout.write(JSON.stringify(f.checkClaudeMdBudget()))`],
93
+ { env: { ...process.env, BONGOS_INSTANCE_ROOT: dir }, encoding: 'utf8' });
94
+ const r = JSON.parse(out);
95
+ assert.equal(r.hardFail, true, 'a pointer to nothing is worse than no pointer');
96
+ assert.ok(r.violations.some((v) => /does not exist/i.test(v)), 'the violation must say the target is missing');
97
+ });
98
+
54
99
  test('CLAUDE.md char budget is ratcheted and ordered (target < ceiling, live file under it)', () => {
55
100
  assert.ok(fitness.ROOT_CHAR_TARGET < fitness.ROOT_CHAR_HARD_MAX, 'target must sit below the hard ceiling');
56
101
  const r = fitness.checkClaudeMdBudget();
@@ -778,6 +823,8 @@ test('identity gate actually CATCHES a re-hardcode (code, URL, HTML) — not a n
778
823
  assert.equal(scanPromptIdentity('x.js', 'const u = "https://amazonprimea.com/x";').length, 1, 'a leak inside a URL must be caught');
779
824
  assert.equal(scanPromptIdentity('x.html', '<title>Amazonprimea</title>').length, 1, 'an HTML title leak must be caught');
780
825
  assert.equal(scanPromptIdentity('x.js', 'const p = "Off the Boats";').length, 1, 'the product name must be caught');
826
+ // task 1002853: the founder's company rode the core status footer because only the product was listed
827
+ assert.equal(scanPromptIdentity('x.html', '<a href="https://hermeslines.com">Hermeslines</a>').length, 1, 'the host company must be caught');
781
828
  });
782
829
 
783
830
  test('identity gate skips comments + instance-injected tokens (no false positives)', () => {
@@ -0,0 +1,60 @@
1
+ // tests/status_company_attribution.mjs — the status page footer's company clause
2
+ // comes from the branding pack, and disappears whole when the pack names no company
3
+ // (task 1002853). Before it, a vanilla instance's CORE-served status page credited
4
+ // the founder's own logistics company as its maker.
5
+ import assert from 'node:assert/strict';
6
+ import { test } from 'node:test';
7
+ import { readFileSync } from 'node:fs';
8
+ import { createRequire } from 'node:module';
9
+
10
+ const require = createRequire(import.meta.url);
11
+ const { applyBrandTokens } = require('../src/bongos/serve-internal.js');
12
+ const { clientBranding } = require('../src/branding.js');
13
+ const { brandTokens } = require('../scripts/status-mirror-sync.js');
14
+
15
+ const PAGE = readFileSync(new URL('../modules/status-ui/public/index.html', import.meta.url), 'utf8');
16
+ const brand = (company) => ({ identity: { productName: 'Acme Rockets', worldName: 'Acme', company }, currency: { label: 'tokens' } });
17
+ const footer = (html) => html.match(/<footer[\s\S]*?<\/footer>/)[0];
18
+ const stamp = (company) => footer(applyBrandTokens(PAGE, brand(company), 'https://acme.example', '', '', '', ''));
19
+
20
+ test('the source page names no company and carries every company slot as a token', () => {
21
+ assert.doesNotMatch(PAGE, /hermeslines|cleveland/i);
22
+ for (const t of ['companyName', 'companySite', 'companyTagline']) assert.ok(PAGE.includes(`{{${t}}}`), `{{${t}}} is missing`);
23
+ });
24
+
25
+ test('a pack with no company drops the whole attribution sentence, not half of it', () => {
26
+ const out = stamp({ name: '', site: 'https://ignored.example', tagline: 'ignored' });
27
+ assert.doesNotMatch(out, /is the work of|ignored/);
28
+ assert.doesNotMatch(out, /\{\{|brand-if/);
29
+ assert.match(out, /Tokens are wrought/, 'the neighbouring footer lines survive');
30
+ });
31
+
32
+ test('a full company renders the linked name and its tagline', () => {
33
+ const out = stamp({ name: 'Acme Corp', site: 'https://acme-corp.example', tagline: 'a rocket works in Dayton' });
34
+ assert.match(out, /<p>Acme is the work of <a href="https:\/\/acme-corp\.example" target="_blank" rel="noopener"><strong>Acme Corp<\/strong><\/a>, a rocket works in Dayton\.<\/p>/);
35
+ assert.doesNotMatch(out, /\{\{|brand-if/);
36
+ });
37
+
38
+ test('a company with no site or tagline renders the bare name, never an empty href or a dangling comma', () => {
39
+ const out = stamp({ name: 'Acme Corp', site: '', tagline: '' });
40
+ assert.match(out, /<p>Acme is the work of <strong>Acme Corp<\/strong>\.<\/p>/);
41
+ assert.doesNotMatch(out, /href=""|, \./);
42
+ });
43
+
44
+ test('company values are escaped like every other token', () => {
45
+ const out = stamp({ name: 'A<b>', site: 'https://x.example/"onmouseover="x', tagline: '' });
46
+ assert.ok(out.includes('<strong>A&lt;b&gt;</strong>'));
47
+ assert.ok(out.includes('href="https://x.example/&quot;onmouseover=&quot;x"'));
48
+ });
49
+
50
+ test('the off-box mirror stamps the footer exactly as the served page does (KEEP IN SYNC)', () => {
51
+ for (const company of [{ name: '', site: '', tagline: '' }, { name: 'Acme Corp', site: 'https://acme-corp.example', tagline: 'a rocket works' }, { name: 'Acme Corp', site: '', tagline: '' }]) {
52
+ assert.equal(footer(brandTokens(PAGE, brand(company), 'https://acme.example')), stamp(company));
53
+ }
54
+ });
55
+
56
+ test('clientBranding exposes the company site and tagline the footer stamps from', () => {
57
+ const c = clientBranding({ identity: { company: { name: 'Acme Corp', site: 'https://acme-corp.example', tagline: 'a rocket works' } } });
58
+ assert.deepEqual(c.identity.company, { name: 'Acme Corp', site: 'https://acme-corp.example', tagline: 'a rocket works' });
59
+ assert.deepEqual(clientBranding({}).identity.company, { name: '', site: '', tagline: '' });
60
+ });