@bongos/core 1.19.297 → 1.19.299

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.297",
6
- "core_contract": "1.19.297",
7
- "source_commit": "1f1b380614ecad230b7399a63883dd4aa65a5c51",
5
+ "core_version": "1.19.299",
6
+ "core_contract": "1.19.299",
7
+ "source_commit": "d591d374828ca13a2d6a3669ba194a33d25f7c82",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-22T19:02:34.784Z",
9
+ "built_at": "2026-08-22T21:42:14.117Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 321,
12
+ "docs_redacted": 322,
13
13
  "agent_docs_stubbed": 22,
14
- "functional_verbatim": 1400,
14
+ "functional_verbatim": 1405,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 1743,
20
- "tree_sha256": "39da631b7c0c17d3b63eb793e9e7b624bf55dbe877a2bdd2a568608076258bf7",
19
+ "file_count": 1749,
20
+ "tree_sha256": "19e6ca4bdb8b1113057e5390e82e3e12947e0d43b2dbae6b81b4c07811ae6dc4",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -347,12 +347,12 @@
347
347
  {
348
348
  "path": "clients/bongos-client/README.md",
349
349
  "mode": "0000644",
350
- "sha256": "6e44e5da05194cc5aae1784d591d5f560dc36527939eda359de794e3d29fdb37"
350
+ "sha256": "162edc8df3b6354b06337ad981f473ea798151002d6c2eda728b25c0545ea70c"
351
351
  },
352
352
  {
353
353
  "path": "clients/bongos-client/bongos-client.global.js",
354
354
  "mode": "0000644",
355
- "sha256": "b05f34f719999b987f9ea6dcecec7bed016a0486ffb43a2ba95fcabbbe7457db"
355
+ "sha256": "f8df65df7eaaccb15fe2a1aeda1c690e377cecc3617b408c4ff8a71f4c79edea"
356
356
  },
357
357
  {
358
358
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -362,17 +362,17 @@
362
362
  {
363
363
  "path": "clients/bongos-client/index.cjs",
364
364
  "mode": "0000644",
365
- "sha256": "5fbf0ea8c5b9eba86cc1d471407d8f4bb1df23af72d4fe7a618576bf67233a14"
365
+ "sha256": "53dec4d0e2958ddb66fe794b74cdc0bb8823fa7d8a5da90a4c2dd731a1bb0e04"
366
366
  },
367
367
  {
368
368
  "path": "clients/bongos-client/index.d.ts",
369
369
  "mode": "0000644",
370
- "sha256": "db6c391a39f2caea99486c5f03993b0cc52e3506835d750a28a4a0b2108bb441"
370
+ "sha256": "85041b30fb2113ca5b3684ae961e67dc2bd5dfdb152064b151af3f0a93a29f31"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/index.mjs",
374
374
  "mode": "0000644",
375
- "sha256": "5ef5dcc11f3713394c6a6225c4206ef8955b27b17c95a47fd51ca43b7965729f"
375
+ "sha256": "f01af61309e843cf15fc8b5c4cb01e8383927890ea1734d91a2ed490424d2d77"
376
376
  },
377
377
  {
378
378
  "path": "clients/bongos-client/package.json",
@@ -1404,20 +1404,25 @@
1404
1404
  "mode": "0000644",
1405
1405
  "sha256": "d68cae6169d7ef251fdf6c721e63a124bd3bf46979ffa51459db435426d24f8b"
1406
1406
  },
1407
+ {
1408
+ "path": "docs/adr/0185-spark-handoff-credit-split.md",
1409
+ "mode": "0000644",
1410
+ "sha256": "51931fe5ae89b14b6c8955e6d6cd43d88a7a6ed05f8c862cdfe56a14302cc990"
1411
+ },
1407
1412
  {
1408
1413
  "path": "docs/adr/README.md",
1409
1414
  "mode": "0000644",
1410
- "sha256": "0eafe881d241706331548cf8212c5e84f2f42167c2ac5688427820fa394d77ef"
1415
+ "sha256": "96f12718ea595a8fff3d3aeafc27013b4ef251724e80d077607addc167533639"
1411
1416
  },
1412
1417
  {
1413
1418
  "path": "docs/api-reference.md",
1414
1419
  "mode": "0000644",
1415
- "sha256": "0c2b5d0fd5e05cbe3b3c06ab10baf7e6af0414d85599519e3ef2eb289008b672"
1420
+ "sha256": "d545aada2bc0127be904c5df12c393c3ab8756f84ef86cc7bcee1348074769f9"
1416
1421
  },
1417
1422
  {
1418
1423
  "path": "docs/api/openapi.json",
1419
1424
  "mode": "0000644",
1420
- "sha256": "ef7e4fbdb912b077c49b15e7ba0dd6333196fe0d82d4462a83c507669fd82767"
1425
+ "sha256": "828558b3bd6cc8d7c9c720eef962e098e4f886ab33360833b2c6d3946acbd1d1"
1421
1426
  },
1422
1427
  {
1423
1428
  "path": "docs/architecture.md",
@@ -1442,12 +1447,12 @@
1442
1447
  {
1443
1448
  "path": "docs/copy-inventory.md",
1444
1449
  "mode": "0000644",
1445
- "sha256": "8cb5bb088aae803e6889571712cc4439fc870c88e104b1bb81dbd5fd1f9b9bd3"
1450
+ "sha256": "10fff8940c3533b2da9e5cd034ee3b85e8f8924615450a037c5dc1118cc515fc"
1446
1451
  },
1447
1452
  {
1448
1453
  "path": "docs/copy-registry.json",
1449
1454
  "mode": "0000644",
1450
- "sha256": "18599cab2b3de43e33513c20cfaa241d3fe0545b861a27942d7f63d11f646750"
1455
+ "sha256": "de5de5aa328f46061c7ee63d2fdea8117141fb18331324f1560cb3344f982a14"
1451
1456
  },
1452
1457
  {
1453
1458
  "path": "docs/design-contract.md",
@@ -1552,7 +1557,7 @@
1552
1557
  {
1553
1558
  "path": "docs/file-map.md",
1554
1559
  "mode": "0000644",
1555
- "sha256": "b017e7a4425f92cc5cbec8d0a5fc192e3225794fb97955acb3689b12dc0de667"
1560
+ "sha256": "fe7af041ba95eb5bdf58b92dcedbe8c7694a1ea8128d980cff566edb6cf32352"
1556
1561
  },
1557
1562
  {
1558
1563
  "path": "docs/handoff-template.md",
@@ -2807,7 +2812,7 @@
2807
2812
  {
2808
2813
  "path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
2809
2814
  "mode": "0000644",
2810
- "sha256": "5fbf0ea8c5b9eba86cc1d471407d8f4bb1df23af72d4fe7a618576bf67233a14"
2815
+ "sha256": "53dec4d0e2958ddb66fe794b74cdc0bb8823fa7d8a5da90a4c2dd731a1bb0e04"
2811
2816
  },
2812
2817
  {
2813
2818
  "path": "modules/dev-box/app/test/unit.mjs",
@@ -2982,7 +2987,7 @@
2982
2987
  {
2983
2988
  "path": "modules/economy/credits.js",
2984
2989
  "mode": "0000644",
2985
- "sha256": "71248889315a29d2a1714ad55ffc685987d862b74e877a29ac2de010bea140f3"
2990
+ "sha256": "7c42fc848a1b7139d7ffa59cc3d81d89db84329b7beae9d5b8c5bc0afefc6f41"
2986
2991
  },
2987
2992
  {
2988
2993
  "path": "modules/economy/migrations/economy_001_fix_gds_shipper_description.sql",
@@ -3464,6 +3469,21 @@
3464
3469
  "mode": "0000644",
3465
3470
  "sha256": "7a102f4fd675910b0c80416c3ed05397d38f977e647fffb00c593732d05a3712"
3466
3471
  },
3472
+ {
3473
+ "path": "modules/hall-ui/public/ideas.css",
3474
+ "mode": "0000644",
3475
+ "sha256": "ee6e640e9e23a7e724a3876171fe20ca9d758458f90bb443968f761d296500f1"
3476
+ },
3477
+ {
3478
+ "path": "modules/hall-ui/public/ideas.html",
3479
+ "mode": "0000644",
3480
+ "sha256": "ad1ef56e043b2c1a93996b93ff098c4ca9555cdcb063df6387ba1d2c92a825e1"
3481
+ },
3482
+ {
3483
+ "path": "modules/hall-ui/public/ideas.js",
3484
+ "mode": "0000644",
3485
+ "sha256": "b3910cd9e1c77e9402f75522a1972c7ed59da784d9bc64a991072465414cb999"
3486
+ },
3467
3487
  {
3468
3488
  "path": "modules/hall-ui/public/index.html",
3469
3489
  "mode": "0000644",
@@ -3632,7 +3652,7 @@
3632
3652
  {
3633
3653
  "path": "modules/hall-ui/public/shell.js",
3634
3654
  "mode": "0000644",
3635
- "sha256": "bfaa74784ee0578fe8e950f55585522a39c892c58f663330a3b724f34a8a0603"
3655
+ "sha256": "cc9fd3033b528ca2e5761054219653926341a6c10ee27ab10b42779cfc3b46a3"
3636
3656
  },
3637
3657
  {
3638
3658
  "path": "modules/hall-ui/public/style.css",
@@ -3747,7 +3767,7 @@
3747
3767
  {
3748
3768
  "path": "modules/ideas/routes/inbox.js",
3749
3769
  "mode": "0000644",
3750
- "sha256": "eafc7ff6f4d9567813cefe2b47333caa4ab79b77ab979e77eb65ac88102a78f1"
3770
+ "sha256": "33a5eadf8400285304e3a1958f25ca104b67c7c5a8c1ac59698cff64b4c70589"
3751
3771
  },
3752
3772
  {
3753
3773
  "path": "modules/ideas/routing.js",
@@ -4542,12 +4562,12 @@
4542
4562
  {
4543
4563
  "path": "package-lock.json",
4544
4564
  "mode": "0000644",
4545
- "sha256": "9fea7a7292ec0de1ea5fea27ec984796c150ed75f0e94e30eca8837f55cbcee6"
4565
+ "sha256": "407f202c0d8cd88cf0f622c4873b9feb1931ceb1dd273723862f8ccd19ec4142"
4546
4566
  },
4547
4567
  {
4548
4568
  "path": "package.json",
4549
4569
  "mode": "0000644",
4550
- "sha256": "8b60b6155a3fd2c2d0110df0404319a6a5da35eeed3ee8d60f61ae009672ed35"
4570
+ "sha256": "ddf2bb2fee835a734a8e1ec4524c33590958b44f82f86a814e953d8ee59b110d"
4551
4571
  },
4552
4572
  {
4553
4573
  "path": "public-docs/index.html",
@@ -6167,7 +6187,7 @@
6167
6187
  {
6168
6188
  "path": "src/bongos/serve-internal.js",
6169
6189
  "mode": "0000644",
6170
- "sha256": "2ce782b00c80482ef9b9d3e4a54a634e73c6d956e13e32cc7e3d2ff63e8282cd"
6190
+ "sha256": "f54837753cf2b432634f044f84f8f198b39b1a18bf48c3ffb3df27f2c3a37cd2"
6171
6191
  },
6172
6192
  {
6173
6193
  "path": "src/bongos/stealth-gate.js",
@@ -6202,7 +6222,7 @@
6202
6222
  {
6203
6223
  "path": "src/module-api.js",
6204
6224
  "mode": "0000644",
6205
- "sha256": "2bfcc90c50b5fd0945b97179e4445602f145896dd1821066cabcd411a8d7a9d9"
6225
+ "sha256": "e714212ca02e064dd7778d83523dcf96f8bfdb8a93f86b87ecde046c8dbba994"
6206
6226
  },
6207
6227
  {
6208
6228
  "path": "src/module-loader/catalog.js",
@@ -7432,7 +7452,7 @@
7432
7452
  {
7433
7453
  "path": "tests/hall_nav.mjs",
7434
7454
  "mode": "0000644",
7435
- "sha256": "7ab365a19909a0a73b446339d5109f8f1f818dd6fdc49c8792a42bde5757e5ed"
7455
+ "sha256": "59de791cd5497e7d73e3d34841f5e816efe36bc34d1580f3e9afbae3055f2f5c"
7436
7456
  },
7437
7457
  {
7438
7458
  "path": "tests/hall_page_gate_map.mjs",
@@ -7489,10 +7509,15 @@
7489
7509
  "mode": "0000644",
7490
7510
  "sha256": "7e2024b3f1fa79a6bdec55b134be6337d4867df0a77fedb205f32b783a3d6193"
7491
7511
  },
7512
+ {
7513
+ "path": "tests/idea_credit_split.mjs",
7514
+ "mode": "0000644",
7515
+ "sha256": "fd96eb0dd472810854d9e0a7ee29725764cf0c3f4ad502c57d6d4a324da25ef5"
7516
+ },
7492
7517
  {
7493
7518
  "path": "tests/idea_develop_spark.mjs",
7494
7519
  "mode": "0000644",
7495
- "sha256": "03d2f692eaa02e85a5f53e89527d4ea1a20c032d4801e2a7acd421eda12ce76c"
7520
+ "sha256": "a498e2dfc87dbb5050d414ff04ebf4178900edb771be384fe91247e452a37a02"
7496
7521
  },
7497
7522
  {
7498
7523
  "path": "tests/idea_full_capture.mjs",
@@ -7502,13 +7527,18 @@
7502
7527
  {
7503
7528
  "path": "tests/idea_full_pass_credit.mjs",
7504
7529
  "mode": "0000644",
7505
- "sha256": "1ae98ae22202e6a6dbf42a48e0133654eeda32eec36b697c59f6b9d630936817"
7530
+ "sha256": "63afe2afd59ff64e290234a0cc8d33a0f77b784d8c10c2d7147fe2ab3c114cd1"
7506
7531
  },
7507
7532
  {
7508
7533
  "path": "tests/idea_grades.mjs",
7509
7534
  "mode": "0000644",
7510
7535
  "sha256": "07cacc97990f0e775342f8b30171c87128e0acb1abd38d64c683c3f257927ebd"
7511
7536
  },
7537
+ {
7538
+ "path": "tests/idea_hall_composer.mjs",
7539
+ "mode": "0000644",
7540
+ "sha256": "cf3071e8180dbb1bdacbafb7a1b40569691afe32b053db0f8de908a5726ca8fe"
7541
+ },
7512
7542
  {
7513
7543
  "path": "tests/idea_quick_guard.mjs",
7514
7544
  "mode": "0000644",
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
5
5
  by hand; it regenerates when the spec changes, so it can never drift from the routes.
6
6
 
7
7
  - API version: **v1** (served at `/api/bongos/v1`)
8
- - 298 operations across 47 resource groups
8
+ - 300 operations across 47 resource groups
9
9
 
10
10
  ## Install
11
11
 
@@ -417,8 +417,12 @@ function createClient(opts = {}) {
417
417
  postInboxIdSpark: (args) => request("POST", "/inbox/{id}/spark", { hasBody: true }, args),
418
418
  // GET /inbox/awaiting-nod — rank: metic+archon — GET /inbox/awaiting-nod
419
419
  getInboxAwaitingNod: (args) => request("GET", "/inbox/awaiting-nod", { hasBody: false }, args),
420
+ // POST /inbox/score — rank: any-builder — POST /inbox/score
421
+ postInboxScore: (args) => request("POST", "/inbox/score", { hasBody: true }, args),
420
422
  // GET /inbox/sparks — rank: any-builder — GET /inbox/sparks
421
423
  getInboxSparks: (args) => request("GET", "/inbox/sparks", { hasBody: false }, args),
424
+ // GET /inbox/template — rank: any-builder — GET /inbox/template
425
+ getInboxTemplate: (args) => request("GET", "/inbox/template", { hasBody: false }, args),
422
426
  },
423
427
  "instance": {
424
428
  // GET /instance — rank: public — GET /instance
@@ -416,8 +416,12 @@ function createClient(opts = {}) {
416
416
  postInboxIdSpark: (args) => request("POST", "/inbox/{id}/spark", { hasBody: true }, args),
417
417
  // GET /inbox/awaiting-nod — rank: metic+archon — GET /inbox/awaiting-nod
418
418
  getInboxAwaitingNod: (args) => request("GET", "/inbox/awaiting-nod", { hasBody: false }, args),
419
+ // POST /inbox/score — rank: any-builder — POST /inbox/score
420
+ postInboxScore: (args) => request("POST", "/inbox/score", { hasBody: true }, args),
419
421
  // GET /inbox/sparks — rank: any-builder — GET /inbox/sparks
420
422
  getInboxSparks: (args) => request("GET", "/inbox/sparks", { hasBody: false }, args),
423
+ // GET /inbox/template — rank: any-builder — GET /inbox/template
424
+ getInboxTemplate: (args) => request("GET", "/inbox/template", { hasBody: false }, args),
421
425
  },
422
426
  "instance": {
423
427
  // GET /instance — rank: public — GET /instance
@@ -51,6 +51,7 @@ export interface GetInboxAwaitingNodResponse { awaiting: unknown; count: unknown
51
51
  export interface GetInboxIdResponse { idea: unknown }
52
52
  export interface GetInboxResponse { ideas: unknown; open_count: unknown }
53
53
  export interface GetInboxSparksResponse { sparks: unknown; count: unknown }
54
+ export interface GetInboxTemplateResponse { template: unknown }
54
55
  export interface GetLeaderboardResponse { leaderboard: unknown; page: unknown }
55
56
  export interface GetLearningsResponse { learnings: unknown }
56
57
  export interface GetMeAchievementsResponse { unlocked: unknown }
@@ -251,6 +252,8 @@ export interface PostInboxIdRatifyRequest { notes_md?: string }
251
252
  export interface PostInboxIdResubmitRequest { field_values: Record<string, unknown>; template_key?: string }
252
253
  export interface PostInboxIdSparkResponse { idea: unknown; sparked: boolean; unchanged: boolean }
253
254
  export interface PostInboxRequest { title: string; body_md?: string; kind?: string; suggested_version?: string; suggested_priority?: number; goal_id?: number; grade?: string; template_key?: string; field_values?: Record<string, unknown> }
255
+ export interface PostInboxScoreRequest { field_values: Record<string, unknown>; template_key?: string }
256
+ export interface PostInboxScoreResponse { score: unknown; fields: unknown; template_key: unknown }
254
257
  export interface PostLearningsRequest { title: string; body_md: string; tags?: string[]; related_files?: string[]; source?: string; source_ref?: string; task_id?: number }
255
258
  export interface PostLearningsResponse { skipped?: boolean; reason?: unknown; learning?: unknown }
256
259
  export interface PostLlmCacheLookupRequest { cache_key?: unknown; tokens_saved_est?: unknown }
@@ -681,8 +684,12 @@ export interface BongosClient {
681
684
  postInboxIdSpark(args?: RequestArgs): Promise<PostInboxIdSparkResponse>;
682
685
  /** GET /inbox/awaiting-nod — rank: metic+archon */
683
686
  getInboxAwaitingNod(args?: RequestArgs): Promise<GetInboxAwaitingNodResponse>;
687
+ /** POST /inbox/score — rank: any-builder */
688
+ postInboxScore(args: RequestArgs & { body: PostInboxScoreRequest }): Promise<PostInboxScoreResponse>;
684
689
  /** GET /inbox/sparks — rank: any-builder */
685
690
  getInboxSparks(args?: RequestArgs): Promise<GetInboxSparksResponse>;
691
+ /** GET /inbox/template — rank: any-builder */
692
+ getInboxTemplate(args?: RequestArgs): Promise<GetInboxTemplateResponse>;
686
693
  };
687
694
  "instance": {
688
695
  /** GET /instance — rank: public */
@@ -413,8 +413,12 @@ export function createClient(opts = {}) {
413
413
  postInboxIdSpark: (args) => request("POST", "/inbox/{id}/spark", { hasBody: true }, args),
414
414
  // GET /inbox/awaiting-nod — rank: metic+archon — GET /inbox/awaiting-nod
415
415
  getInboxAwaitingNod: (args) => request("GET", "/inbox/awaiting-nod", { hasBody: false }, args),
416
+ // POST /inbox/score — rank: any-builder — POST /inbox/score
417
+ postInboxScore: (args) => request("POST", "/inbox/score", { hasBody: true }, args),
416
418
  // GET /inbox/sparks — rank: any-builder — GET /inbox/sparks
417
419
  getInboxSparks: (args) => request("GET", "/inbox/sparks", { hasBody: false }, args),
420
+ // GET /inbox/template — rank: any-builder — GET /inbox/template
421
+ getInboxTemplate: (args) => request("GET", "/inbox/template", { hasBody: false }, args),
418
422
  },
419
423
  "instance": {
420
424
  // GET /instance — rank: public — GET /instance
@@ -0,0 +1,129 @@
1
+ # 0185 — The spark-handoff credit split: 70% developer, 30% spark author
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-08-22
5
+ - **Tasks:** [#1002923](https://cloudbongos.com/builders#/task/1002923) (BV1.R147, goal 1000062 — three grades of idea). Completes the spark chain: [#1002920](https://cloudbongos.com/builders#/task/1002920) (the mark), [#1002921](https://cloudbongos.com/builders#/task/1002921) (the queue), [#1002922](https://cloudbongos.com/builders#/task/1002922) (the pickup)
6
+ - **Extends:** [ADR 0172](<redacted>.md) — the ideator credit lane. That ADR built the streams and paid `captured_by`; this one decides what happens when `captured_by` is not the only person who made the idea.
7
+ - **Related:** ADR 0023 (the original idea-promotion slice), 0146 (reward-mode machinery), 0054 (cost-plus)
8
+
9
+ ## Context
10
+
11
+ ADR 0172 shipped the ideator credit lane: stream 1 pays 5 credits (scaled by idea
12
+ grade) for every task shipped under an idea, stream 2 pays 5 credits once when a
13
+ Full Idea clears the completeness bar. Both paid `idea_inbox.captured_by` — the
14
+ person who filed the idea — because at the time that was the only person an idea
15
+ had.
16
+
17
+ Goal 1000062 then built the **spark handoff**. An author marks a quick idea as a
18
+ Big Idea Spark ("I have the spark but not the full picture, someone develop
19
+ this" — R144); that mark is the consent that makes cross-builder development
20
+ fair. The spark becomes browsable (R145), and another builder develops it into a
21
+ Full Idea in place, preserving the original author while being recorded as its
22
+ developer (R146, `ideas_grades.developed_by`).
23
+
24
+ That created a person the credit model had no answer for. Two builders now make
25
+ one Full Idea: one had the thought, one wrote the five fields. Both streams still
26
+ paid only the author.
27
+
28
+ **R146 therefore deliberately shipped paying nothing at all.** Not an oversight —
29
+ a refusal to guess. `awardIdeaFullPassCredit`'s idempotency predicate is
30
+ `(builder_id, reason)`, so a payment to the *developer* would **not** have blocked
31
+ a later payment to the *author*: the same idea would have paid twice. Choosing a
32
+ recipient at that call site was not merely premature, it was unsafe. The develop
33
+ route left the money alone and named this task as the owner of the decision.
34
+
35
+ The result was a real gap in the meantime: a developed Full Idea that cleared the
36
+ bar received stream 2 **never** — the only path that could pay it was the author
37
+ resubmitting their own idea.
38
+
39
+ ## Decision
40
+
41
+ ### 1. 70% to the developer, 30% to the spark author — on both existing streams
42
+
43
+ The owner's call, 2026-08-22. The developer takes the larger share, and the
44
+ reasoning is behavioural rather than sentimental: **developing someone else's
45
+ spark is the scarce act the queue depends on.** At an even split, developing a
46
+ spark pays half what authoring your own Full Idea pays for the same writing work,
47
+ so the rational move is always to write your own and the R145 queue stays a list
48
+ nobody reads. The majority share is what makes the pickup surface function.
49
+
50
+ The author is not left thin. They keep 30% of every split **and** their share of
51
+ stream 1 on every task shipped under the idea, for as long as the idea keeps
52
+ producing work. The thought keeps earning; it simply stops being the only
53
+ contribution the ledger recognises.
54
+
55
+ One ratio, applied to **both** streams — the immediate pass credit and the
56
+ trailing per-task credit — so there is a single rule to explain rather than a
57
+ table of cases. Stream 3 (the board-room payout, [#1002999](https://cloudbongos.com/builders#/task/1002999),
58
+ not yet built) inherits the same helper when it lands.
59
+
60
+ ### 2. A policy constant in `credits.js`, not a table
61
+
62
+ `IDEA_DEVELOPER_SHARE = 0.70` sits beside the pass bar and the quick factor, per
63
+ ADR 0172's own consequence ("thresholds/factors are policy constants in
64
+ `credits.js`", following the ADR 0023 precedent). A share of someone's earnings
65
+ deserves a review and a commit, not a runtime edit. It is one constant, so a
66
+ project that wants a different balance changes one line — which is the recorded
67
+ owner philosophy for this goal: a simple base, designed to be altered.
68
+
69
+ ### 3. The economy module decides who is paid — the caller no longer can
70
+
71
+ `awardIdeaFullPassCredit` now reads `captured_by` and `developed_by` from the
72
+ database itself (`ideaCreditParties`) instead of trusting the `authorId` its
73
+ caller passes; the argument survives only as a fallback for an idea the lookup
74
+ cannot see. `awardIdeaTaskShipCredit` already read the idea row and simply selects
75
+ `developed_by` alongside.
76
+
77
+ This is the structural half of the decision, and it is what makes R146's caution
78
+ unnecessary going forward. The reason the develop route could not safely pay was
79
+ that *the recipient was chosen at the call site*. With the payees derived in one
80
+ place, no caller can direct money at the wrong builder, and the develop route now
81
+ books the split like any other path — **it hands over an idea and a score, never
82
+ a recipient.**
83
+
84
+ ### 4. Three arithmetic properties, each a real bug if missed
85
+
86
+ `splitIdeaCredit` is pure and carries them:
87
+
88
+ - **The total is conserved.** The developer's share is rounded and the author gets
89
+ *the remainder*. Rounding both independently pays 6 credits out of a 5-credit
90
+ payout (`round(3.5) + round(1.5) = 4 + 2`).
91
+ - **A self-developed idea collapses to one payee.** R146 deliberately permits an
92
+ author to develop their own spark. Emitting two rows for one builder would not
93
+ double-pay — it would **under**-pay, because the idempotency predicate is
94
+ `(builder_id, reason)` and the second insert is silently refused, so the builder
95
+ would receive one of their two shares. The comparison normalises with `String()`
96
+ because `bigint` columns arrive as strings: a type mismatch must not become a
97
+ phantom second payee.
98
+ - **Zero-value rows are dropped.** A 1-credit payout splits to 1/0; a 0-credit
99
+ ledger row reads like a payment that was not made.
100
+
101
+ Ids otherwise pass through **unconverted**. `builder_id` is a `bigint`, so
102
+ `Number()`-ing it risks precision on a large id and would change the value type
103
+ the pre-R147 code fed straight into the `INSERT`.
104
+
105
+ ### 5. `builder_id` in the idempotency predicate is now load-bearing
106
+
107
+ It entered as an index optimisation — narrowing the `NOT EXISTS` to one builder's
108
+ rows via `idx_credit_log_builder` instead of scanning a growing `credit_log` (the
109
+ R143/IC2 grader finding). Under a split it is also **correctness**: two payees are
110
+ booked under one `reason`, so a reason-only predicate would refuse the second.
111
+ A partially-booked split therefore completes on the next call, and `credited`
112
+ reports only what was newly booked.
113
+
114
+ ## Consequences
115
+
116
+ - **The spark queue has a reason to be picked up.** The chain R144 → R145 → R146
117
+ now ends in a payment rather than in attribution alone.
118
+ - **A developed Full Idea gets stream 2 at develop time**, closing the gap R146
119
+ left. It is fail-open: the development has already committed, and a credit-lane
120
+ hiccup must never roll back somebody's work.
121
+ - **One place decides who earns from an idea.** Future callers inherit the split
122
+ for free and cannot get the recipient wrong.
123
+ - **Not decided here:** stream 3's split (it ships with the Board Room, task
124
+ 1002999) and whether `origin='develop'` in `ideas_task_lineage` belongs to
125
+ whoever promotes a *developed* idea into a task. ADR 0172 §5 says the lineage
126
+ row is "set at promotion and at develop (R146)", but R146 creates no task —
127
+ developing a spark produces a Full Idea, not work — so that origin is still
128
+ unwired, deliberately, rather than invented. It changes who stream 1 pays, so it
129
+ deserves its own decision.
@@ -258,5 +258,6 @@ This keeps the decision history honest and traceable.
258
258
  | 0182 | [**Project visibility is TWO axes: a derived publish gate and a stored join door** ([task 1002320](https://cloudbongos.com/builders#/task/1002320), goal 1000046). Goal 1000046 seeded 31 tasks each citing "per R01" — this ADR — so nothing in the goal could start until it landed: it gated **29 open tasks**, the largest single chokepoint in the repo, while itself parked at `backlog` with no dependencies. The spec its planning task cites was never written, so this is the design of record. The goal's criterion says **four** states (Public/Private/Stealth/Unlisted) and R04 says **three** stored plus a derived dark-matter; both are right and conflating them is the trap. There are two INDEPENDENT axes: **publishability** (DERIVED from the identity gate — name + description, per the owner interview) decides whether a project is on the map at all, and **the join door** (STORED `visibility ∈ public|private|stealth`, owner-set) decides how it renders and who gets in. Four user-facing states = 3 × publishable + one derived state that collapses all three. The column name `visibility` is a mild lie kept for consistency with `goals.visibility` (ADR 0112) — it does NOT decide visibility, publishability does — and the ADR is the mitigation. All three stored states are VISIBLE; only the derived state is invisible, which is what makes the 3+1 split honest rather than a workaround. `private` inherits ADR 0112's exact meaning (visible-but-closed); `stealth` exposes EXISTENCE but not IDENTITY, and its redaction is **server-side in the feed** — the naive client-side version leaks to anyone opening the network tab, and the orbs page is a static site OUTSIDE this repo (R09) so it could never be enforced there. Three mechanisms touch "does this appear" and are separated: `status` (operational), `visibility` (owner), `featured` (Archon editorial) — on the map iff `status='active' AND publishable`, with `featured` only ranking among those. That is a real behaviour change: today's predicate is `featured=true AND status='active'`, so **featuring is currently load-bearing for visibility at all** and the goal's owner-control premise silently does not work without it. Visibility is owned by the INSTANCE and the hub row is a CACHE (ADR 0141 §3 + the admin-console spike's D1) — so `owner_github_id` being "advisory, not an authority" is CORRECT rather than a gap, R05 moves to an instance surface, and R08's absent-report default is fail-closed (unreported ⇒ dark matter, off the map rather than exposed by omission). Per-state join rules compose with the separate `open|closed` join policy ([task 1002817](https://cloudbongos.com/builders#/task/1002817)) by one rule: **visibility sets the ceiling, join policy may only narrow** — otherwise the two settings are a coin-flip decided by evaluation order. Finally, `stealth` COLLIDES with the existing instance-wide pre-launch password gate (`STEALTH_PASSWORD`, `src/bongos/stealth-gate.js`), which means nearly the opposite (a whole instance made unreadable vs a project publicly on the map, anonymously); per ADR 0174 the product meaning keeps the word and the infra rename is filed separately rather than decided by an ADR about visibility. Rejected: a stored 4-valued enum (makes `unlisted` compete with `private`, and lets publishable+unlisted disagree), a separate `published` boolean (can drift from the identity it summarises; derived cannot), and keeping `featured` as the visibility gate (an owner who sets public and appears nowhere has not been given control).](<redacted>.md) | platform-identity / project visibility |
259
259
  | 0183 | [**A done-when criterion closes itself; the review queue becomes a place to look** ([task 1002069](https://cloudbongos.com/builders#/task/1002069), goal 1000072, owner request 2026-07-05). ADR 0086 §6 made `satisfied` reachable exactly one way — a Metic+ calling `POST /done-when/:id/satisfy` — even though the signal it gated on is unambiguous (**every** gating task shipped) and a human confirming it adds no information. When nobody runs `/goal-review` the result is not a careful pause but a **lying board**: this session measured goal 1000072 at `6/9 shipped, 0/5 criteria`. Now one helper, `doneWhen.autoSatisfyShippedCriteria(exec, {taskId})`, runs from **two** places for two different reasons — inside `shipTask`'s txn (scoped, **immediate**, on the txn client so a rolled-back ship cannot leave a goal achieved) and unscoped on every `publish-reconciler` tick (**backlog drain** for criteria whose tasks shipped before this existed, since nothing will ship against them again, plus **self-heal**). Idempotent by construction — it reads only `satisfied=false` rows — which is what makes an every-tick sweep safe. **The load-bearing subtlety is the delivery guard.** Auto-close needs BOTH "nothing still pending" AND **≥ 1 task actually `shipped`**; the second is not redundant, because since [task 1002651](https://cloudbongos.com/builders#/task/1002651) made `abandoned` terminal-not-pending, a criterion whose tasks were **all cut** satisfies the first clause *vacuously* and would auto-close on ZERO delivered work, cascading its goal to `achieved` (measured: `buildCriterionProgress` returns `pending_review:true` for exactly that shape). Yet `pending_review` **keeps** that wider meaning on purpose — it asks "should a human LOOK at this", and 1002651 chose that an all-abandoned criterion surfaces so someone decides whether it still means anything. So: everything that auto-closes was flagged; not everything flagged auto-closes. An earlier draft "aligned" the two predicates and broke that intent — `tests/criterion_progress.mjs` caught it; **do not re-align them**, the gap is the design. `/goal-review` is kept, demoted from gate to viewing surface; manual `POST /satisfy` stays for what automation cannot judge (a criterion with no linked tasks never auto-closes). Honest limits recorded: auto-satisfy cannot help a criterion nothing is LINKED to, and the in-txn close logs before commit (accepted — threading the summary out through `withTx` would cost ~5 lines in the over-threshold `db.js` under shrink-only ratchet policy). Rejected: sweep-only (up to 5 min to see your own goal close), hook-only (never drains the backlog), a stored `pending_review` column (second source of truth), deleting `/goal-review`.](<redacted>.md) | lifecycle / goal tier |
260
260
  | 0184 | [**A ship must account for itself: `shipTask` requires a land proof or a declared no-artifact** ([task 1002483](https://cloudbongos.com/builders#/task/1002483), goal 1000024). `db.shipTask` is the confirmed→shipped flip and, since [ADR 0120](<redacted>.md), where the CREDIT is booked — yet its only precondition was `WHERE status = 'confirmed'`, nothing about whether code reached main. The two AUTOMATED paths each proved the land first; the MANUAL route passed nothing, so a task confirmed with no pushed code could be shipped by its claim holder **or by any Metic+ sweeping `/merge-mode`**, booking its `task.shipped` credit. It stayed untracked for two months because its tracking task was closed in June asserting task 1001547 had delivered the gate — it had not, blocker 1000047's own final update says so, and the code agreed with the blocker rather than the closure note: **a hole hidden by a record nobody checked**, which is the same failure the gate is about. Decision: the gate lives at the WRITE, not the route (a route gate leaves the invariant unenforced at the layer that moves the ledger, so the next caller reopens it silently), and `shipTask` is FAIL-CLOSED on a required `landAssurance`. TWO kinds, and the second is why this does not make things worse: `proof` (this task's commit is on main) and **`no_artifact`** — a deliberate DB-only ship, an explicitly supported shape (CLAUDE.md "Direct DB writes are work too") that [task 1002478](https://cloudbongos.com/builders#/task/1002478) documents as a dead end below Archon. A naive proof-only gate would have made 1002478 strictly worse; naming no-artifact as a KIND turns it from an absence the gate must be talked out of into a recorded answer. Both carry a reason, audited post-commit and best-effort (an audit miss must never roll back a landed ship). `ship.js` now declares its own `--db-only`/`--allow-empty` lands, without which this fix would have regressed the very flow CLAUDE.md calls supported. Rejected: (b) gate only the route — leaves the write unguarded; (c) record the residual as tolerable — defensible on blast radius and genuinely close, but it would have been the FOURTH record asserting this was handled with nothing checkable behind it. Does NOT gate confirm: a codeless confirm is still accepted, it simply cannot reach `shipped` or pay.](<redacted>.md) | lifecycle / integrity |
261
+ | 0185 | [**The spark-handoff credit split: 70% developer, 30% spark author** ([task 1002923](https://cloudbongos.com/builders#/task/1002923), BV1.R147, goal 1000062 — completing the chain [task 1002920](https://cloudbongos.com/builders#/task/1002920) mark → [task 1002921](https://cloudbongos.com/builders#/task/1002921) queue → [task 1002922](https://cloudbongos.com/builders#/task/1002922) pickup). [ADR 0172](<redacted>.md) built the ideator streams and paid `captured_by`, the only person an idea then had. The spark handoff created a second: R146 develops a spark IN PLACE, preserving the author while recording a `developed_by`. **R146 therefore shipped paying NOTHING on purpose** — not an oversight but a refusal to guess, because `awardIdeaFullPassCredit`'s idempotency predicate is `(builder_id, reason)`, so paying the DEVELOPER would not have blocked a later payment to the AUTHOR and one idea would have paid twice; the cost of that caution was that a developed Full Idea received stream 2 **never** unless its author resubmitted. Owner decision (2026-08-22): **70/30 favouring the developer**, on BOTH existing streams, one ratio so there is one rule to explain. The reasoning is behavioural, not sentimental — developing someone else's spark is the scarce act the queue depends on, and at an even split it pays HALF what authoring your own Full Idea pays for the same writing work, so the rational move is always to write your own and the R145 queue stays a list nobody reads. The author keeps 30% plus their share of stream 1 on every task shipped under the idea, forever. `IDEA_DEVELOPER_SHARE = 0.70` is a **policy constant in `credits.js`** beside the pass bar and quick factor (ADR 0172's own consequence, the ADR 0023 precedent): a share of someone's earnings deserves a review and a commit, not a runtime edit. **The structural half is what retires R146's caution:** the economy module now derives the payees itself (`ideaCreditParties` reads `captured_by` + `developed_by`), so the caller can no longer choose a recipient — the develop route hands over an idea and a score, never a payee, and books the split like any other path (fail-open; the development has already committed). Three arithmetic properties, each a real bug if missed: the total is **conserved** (developer rounded, author gets the REMAINDER — rounding both pays 6 out of a 5-credit payout); a **self-developed** idea collapses to ONE payee, because two rows for one builder would silently UNDER-pay under the per-builder idempotency predicate, not double-pay (the comparison normalises via `String()` since `bigint` arrives as a string, so a type mismatch cannot become a phantom payee); and **zero-value rows are dropped**. Ids otherwise pass through unconverted — `Number()`-ing a `bigint` risks precision. `builder_id` in the idempotency predicate, which entered as an index optimisation (the R143/IC2 grader finding), is now **load-bearing for correctness**: two payees share one `reason`, so a reason-only predicate would refuse the second, and a partially-booked split completes on the next call. **Not decided here:** stream 3's split (ships with the Board Room, task 1002999), and whether `origin='develop'` in `ideas_task_lineage` belongs to whoever promotes a DEVELOPED idea into a task — ADR 0172 §5 says the row is "set at promotion and at develop (R146)", but R146 creates no task, so that origin stays deliberately unwired rather than invented; it changes who stream 1 pays.](<redacted>.md) | economy / ideator lane |
261
262
 
262
263
  > ⚠️ **Numbering collision (known):** two ADRs share `0008`. The numbers were assigned in parallel sessions before the lock could be enforced. The files are kept under their existing filenames to preserve git history, but the table disambiguates them as `0008-a` / `0008-b`. New ADRs should resume at `0040` to avoid further collisions. (`0024` is also a real on-disk duplicate: the cloneable-repo/local-first-memory ADR and the multi-agent-system-architecture ADR were both numbered `0024` in parallel; both keep their filenames, disambiguated as `0024-a` / `0024-b` like `0008`. Likewise `0025` ended up with two on-disk files — the offsite-backup ADR and the structured-criterion↔task-link ADR — both kept under their existing filenames and disambiguated as `0025-a` / `0025-b`; separately, the BFG ADR had also claimed `0025` on 2026-05-30 and yielded to `0026`. A third happened 2026-06-06: `0036` was claimed in parallel by the builders-subdomain ADR ([#726](https://example.com/builders#/task/726)) and this Discord-channels ADR ([#727](https://example.com/builders#/task/727)); the Discord-channels ADR yielded to `0037`. A fourth landed 2026-06-10: `0044` was claimed in parallel by the palette-replacement ADR and the per-box game-preview ADR ([#897](https://example.com/builders#/task/897)); both keep their filenames, disambiguated as `0044-a` / `0044-b` like `0008`. A fifth was caught pre-land 2026-06-13: `0050` was claimed in parallel by the device-flow-admission ADR ([#1000](https://example.com/builders#/task/1000)) and the sandbox-for-everyone ADR ([#1001](https://example.com/builders#/task/1001)); the latter yielded to `0052` before merging, so there is no `0050` duplicate. A sixth was caught pre-land 2026-06-21: the tool-agnostic-design-layer ADR ([#1375](https://example.com/builders#/task/1375)) first collided at `0079` with the value-gated-autonomous-engagement ADR, then at `0080` with the llm-cache-api-transport ADR (both part of the 0075–0080 LLM-cost-reduction series, landed on `main` in parallel); it yielded to `0081` before merging, so there is no `0079`/`0080` design-layer duplicate. A seventh landed 2026-06-23: `0084` was claimed in parallel by the auto-derived-per-task-rank-floor ADR and the remove-default-spend-cap ADR (task 1499); the rank-floor ADR landed on `main` first, so the spend-cap ADR yielded to `0085`, leaving no `0084` duplicate. An eighth landed 2026-06-27: `0095` was claimed in parallel by the borrowed-memory-and-retrieval-concepts ADR (PR #459, landed first) and the cross-agent-context-management ADR ([#1651](https://example.com/builders#/task/1651), PR #460); both keep their filenames, disambiguated as `0095-a` / `0095-b` like `0008`. These two are companions — `0095-a` adopts the memory/retrieval concepts and explicitly defers the grep-vs-semantic question to `0095-b`.)