@bongos/core 1.24.17 → 1.24.19

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/bongos/package-core.js",
5
- "core_version": "1.24.17",
6
- "core_contract": "1.24.17",
7
- "source_commit": "f7f9e7577824a2b7f8ddb83390d30f54eeec99a1",
5
+ "core_version": "1.24.19",
6
+ "core_contract": "1.24.19",
7
+ "source_commit": "3a975dad2b3edf44743cb62b149866e7604c00bd",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-10-30T21:15:09.518Z",
9
+ "built_at": "2026-10-30T22:23:46.466Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 632,
13
13
  "agent_docs_stubbed": 32,
14
- "functional_verbatim": 3798,
14
+ "functional_verbatim": 3802,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 4463,
20
- "tree_sha256": "64b322c3ab81616c72e8aaec297d36306593b337af36498181187eb6aa237648",
19
+ "file_count": 4467,
20
+ "tree_sha256": "5c63a13f123c8ddd1571c37e182c79b9b8e6da29707be38187c10bd014fe973c",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -332,12 +332,12 @@
332
332
  {
333
333
  "path": "clients/bongos-client/README.md",
334
334
  "mode": "0000644",
335
- "sha256": "a2e94297703074317b5bceb88168c4d7c2caa79d4619b2dad16445a8eacd85e8"
335
+ "sha256": "93014d9ba68f4a28c1c23ca623762df541883df9201aad5ffdfd53bee22a0b8d"
336
336
  },
337
337
  {
338
338
  "path": "clients/bongos-client/bongos-client.global.js",
339
339
  "mode": "0000644",
340
- "sha256": "dee0d76f41a5c0449c9bb506287911470a78744370c225247eb80f74a049c7fe"
340
+ "sha256": "f4ef4c8a0d192356bcbf81a20d793ad368506a245f9b392d4654776fde6539f0"
341
341
  },
342
342
  {
343
343
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -347,17 +347,17 @@
347
347
  {
348
348
  "path": "clients/bongos-client/index.cjs",
349
349
  "mode": "0000644",
350
- "sha256": "4277b81ea894f709e793e1cc2b9080ca65ac2c50e383e994082c2af3a973d467"
350
+ "sha256": "fafbd80941536f67f85b55c5c250df1ed152398f30ebec2820d431c99676ffb3"
351
351
  },
352
352
  {
353
353
  "path": "clients/bongos-client/index.d.ts",
354
354
  "mode": "0000644",
355
- "sha256": "9108d90c261aebdbb7e5077c0b6bd8eb678ac88d87a7c989bee01643ef0d8037"
355
+ "sha256": "0e60eb71a4c912b79c2cac3bc338403883667da5c6f871ed811f21dec58d33f9"
356
356
  },
357
357
  {
358
358
  "path": "clients/bongos-client/index.mjs",
359
359
  "mode": "0000644",
360
- "sha256": "5fe1ff79bf2840651074640d90f9daab7db4455eddf1d2ace559589bc8b74f70"
360
+ "sha256": "68e375e1c32558fc6e442849bac87b2a82433d333bee255d3aeb0904b9c3f5a1"
361
361
  },
362
362
  {
363
363
  "path": "clients/bongos-client/package.json",
@@ -2457,17 +2457,17 @@
2457
2457
  {
2458
2458
  "path": "docs/api-reference.md",
2459
2459
  "mode": "0000644",
2460
- "sha256": "2eeb56594f7d73ba944f8154c1ad7dad95be7e3b3979298ca84607db0e3d5ee8"
2460
+ "sha256": "57e77a6ffdbe2d558c088fce69e154b3b595b4d6d10b5053ad4ba0043cb00c46"
2461
2461
  },
2462
2462
  {
2463
2463
  "path": "docs/api/openapi.json",
2464
2464
  "mode": "0000644",
2465
- "sha256": "2233f1eced2740296b71eb4bbe3539c6c359d757aa9185fb914c5dde9bcb3549"
2465
+ "sha256": "d2e12182597058030c086d3283f652f8d8e2b2e62900c9babed2eba71a97996a"
2466
2466
  },
2467
2467
  {
2468
2468
  "path": "docs/architecture.md",
2469
2469
  "mode": "0000644",
2470
- "sha256": "9aafe52bde706254b562411ff290104c0aa5dbe8a29e2e3e61fec89b2f3bb24c"
2470
+ "sha256": "ac90efe1fecf89564c59896f69f6131923dfbfdc480f514af9e86802eb1041de"
2471
2471
  },
2472
2472
  {
2473
2473
  "path": "docs/branding-contract.md",
@@ -3002,7 +3002,7 @@
3002
3002
  {
3003
3003
  "path": "docs/module-api-changelog.md",
3004
3004
  "mode": "0000644",
3005
- "sha256": "1cd6c004501b1299126de68b3872cc35e7a015bba3362fc50b155d50db3632d9"
3005
+ "sha256": "b4f62fd2bf2938231647a8b0e7b1337e907a34ac8f43e8e6cc0e992a98516980"
3006
3006
  },
3007
3007
  {
3008
3008
  "path": "docs/modules-contract.md",
@@ -4309,6 +4309,11 @@
4309
4309
  "mode": "0000644",
4310
4310
  "sha256": "e7be74430d0d9349b4f9820ff3f202ef03d8c28363fecbaa532c4b9c119e77ec"
4311
4311
  },
4312
+ {
4313
+ "path": "migrations/core_290_builder_payouts.sql",
4314
+ "mode": "0000644",
4315
+ "sha256": "6a8ca9343a4e7d9657baaadb89f42fe76f9354ce739d09ea51569d12e01d8706"
4316
+ },
4312
4317
  {
4313
4318
  "path": "modules/agents/CLAUDE.md",
4314
4319
  "mode": "0000644",
@@ -5242,7 +5247,7 @@
5242
5247
  {
5243
5248
  "path": "modules/economy/module.json",
5244
5249
  "mode": "0000644",
5245
- "sha256": "b958458c140d149228f8ed40487f3e982466cf79be585691d4f1ffcbef13480d"
5250
+ "sha256": "0c1dd2a3a6f467697bdd72443d05cc3f99ec51b2b4e6d2efdd2e0f57a03cf6c9"
5246
5251
  },
5247
5252
  {
5248
5253
  "path": "modules/economy/policy.js",
@@ -5287,7 +5292,7 @@
5287
5292
  {
5288
5293
  "path": "modules/economy/routes/project-account.js",
5289
5294
  "mode": "0000644",
5290
- "sha256": "d2a4dd604dd29ad6b0da1d7d8fadba423b6279fd46866512cd0cc4fbb37ad1cb"
5295
+ "sha256": "1e61263bf8b0aaf2ad0e677fb4a57ab2c02888c296de4ca8fc76ccd2c135f235"
5291
5296
  },
5292
5297
  {
5293
5298
  "path": "modules/economy/routes/reward.js",
@@ -11692,12 +11697,12 @@
11692
11697
  {
11693
11698
  "path": "package-lock.json",
11694
11699
  "mode": "0000644",
11695
- "sha256": "53297fe3ccc01d30cac66baffc1c3ddc528b91d3bf36d6c626e97477405a6216"
11700
+ "sha256": "e0cedb6d1124be871e92e8fd4f27ef7eeec6ef68df68255895dc7ef6452f9676"
11696
11701
  },
11697
11702
  {
11698
11703
  "path": "package.json",
11699
11704
  "mode": "0000644",
11700
- "sha256": "f8bc5d960904c6118c3ff73f3181bc1ae4761abccba9f1df71719908ccf12a65"
11705
+ "sha256": "dddc98a9784db55a3d203b3625687dde3cfda384fb3cedca3e8856ba1eefa34d"
11701
11706
  },
11702
11707
  {
11703
11708
  "path": "public-docs/index.html",
@@ -11717,7 +11722,7 @@
11717
11722
  {
11718
11723
  "path": "release-notes.json",
11719
11724
  "mode": "0000644",
11720
- "sha256": "33bb0faf10fbdb3afcf054c4ab3be42ae54139ee69f7df8b84340a6d3318466b"
11725
+ "sha256": "9cb23ae01651ae9d0f02febefb647e7cce2567bcdef2cb7d2073bbe27114b7b8"
11721
11726
  },
11722
11727
  {
11723
11728
  "path": "scripts/bongos/CLAUDE.md",
@@ -12947,7 +12952,7 @@
12947
12952
  {
12948
12953
  "path": "scripts/bongos/run-unit-tests.js",
12949
12954
  "mode": "0000644",
12950
- "sha256": "16b3277dc426f3bb2c7043d1c0b466b7db65c75a277c4e77864457152624cf2a"
12955
+ "sha256": "52b452c7f022282371d0583561498737716103358ed8e010eb9734efe77f2e89"
12951
12956
  },
12952
12957
  {
12953
12958
  "path": "scripts/bongos/runner-drift.js",
@@ -15139,6 +15144,11 @@
15139
15144
  "mode": "0000644",
15140
15145
  "sha256": "f09f297371563a361002d1443414aa5ab65da36ad5e68bfadb634c659aeda6f3"
15141
15146
  },
15147
+ {
15148
+ "path": "src/bongos/builder-payouts.js",
15149
+ "mode": "0000644",
15150
+ "sha256": "b84ffb276778a5ddf018618c689b656c2d5d3a810af9e829dcb5fd20e6d6e81f"
15151
+ },
15142
15152
  {
15143
15153
  "path": "src/bongos/cascade-dispatch.js",
15144
15154
  "mode": "0000644",
@@ -15492,7 +15502,7 @@
15492
15502
  {
15493
15503
  "path": "src/bongos/routes/payout-approvals.js",
15494
15504
  "mode": "0000644",
15495
- "sha256": "7528a05d03970ea359b8b15e8bdd2a8cc56835e3c867f7662f09b3adf38ea8d5"
15505
+ "sha256": "5575f0616b45c78f57a8fa237ead916f3b04e4eae394f807603d7bf6cb53a912"
15496
15506
  },
15497
15507
  {
15498
15508
  "path": "src/bongos/routes/payout-gates.js",
@@ -15582,7 +15592,7 @@
15582
15592
  {
15583
15593
  "path": "src/module-api.js",
15584
15594
  "mode": "0000644",
15585
- "sha256": "06f9627d1fd34e3166cb8f6a16db6257307eec862791c77d5e17568dcf83e156"
15595
+ "sha256": "8c2086ebd21b5a8ab1e3b15c65e514db0f7460405b2ef08f6e4a4c1e456ad9c0"
15586
15596
  },
15587
15597
  {
15588
15598
  "path": "src/module-loader/catalog.js",
@@ -16399,6 +16409,16 @@
16399
16409
  "mode": "0000644",
16400
16410
  "sha256": "2eecaaa02ad5d2cd8e25449d66dc86aa1884278dbf72656c0d9401129034e247"
16401
16411
  },
16412
+ {
16413
+ "path": "tests/builder_payouts.mjs",
16414
+ "mode": "0000644",
16415
+ "sha256": "45d49e84f826115c43bf9f01a42eae4ee70ffe26fdc02acf303b345c9850d397"
16416
+ },
16417
+ {
16418
+ "path": "tests/builder_payouts_db.mjs",
16419
+ "mode": "0000644",
16420
+ "sha256": "1676f0b2452e0d834df2b49974d4699f918e223e56d2f4193ffe87339b6f1f4a"
16421
+ },
16402
16422
  {
16403
16423
  "path": "tests/builder_tester_tag.mjs",
16404
16424
  "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
- - 657 operations across 83 resource groups
8
+ - 659 operations across 83 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -1037,6 +1037,10 @@ function createClient(opts = {}) {
1037
1037
  getPayoutsApprovals: (args) => request("GET", "/payouts/approvals", { hasBody: false }, args),
1038
1038
  // POST /payouts/approve — rank: archon — POST /payouts/approve
1039
1039
  postPayoutsApprove: (args) => request("POST", "/payouts/approve", { hasBody: true }, args),
1040
+ // GET /payouts/builder-payouts — rank: archon — GET /payouts/builder-payouts
1041
+ getPayoutsBuilderPayouts: (args) => request("GET", "/payouts/builder-payouts", { hasBody: false }, args),
1042
+ // POST /payouts/builder-payouts — rank: archon — POST /payouts/builder-payouts
1043
+ postPayoutsBuilderPayouts: (args) => request("POST", "/payouts/builder-payouts", { hasBody: true }, args),
1040
1044
  // POST /payouts/contracts — rank: archon — POST /payouts/contracts
1041
1045
  postPayoutsContracts: (args) => request("POST", "/payouts/contracts", { hasBody: true }, args),
1042
1046
  // POST /payouts/freezes — rank: archon — POST /payouts/freezes
@@ -1036,6 +1036,10 @@ function createClient(opts = {}) {
1036
1036
  getPayoutsApprovals: (args) => request("GET", "/payouts/approvals", { hasBody: false }, args),
1037
1037
  // POST /payouts/approve — rank: archon — POST /payouts/approve
1038
1038
  postPayoutsApprove: (args) => request("POST", "/payouts/approve", { hasBody: true }, args),
1039
+ // GET /payouts/builder-payouts — rank: archon — GET /payouts/builder-payouts
1040
+ getPayoutsBuilderPayouts: (args) => request("GET", "/payouts/builder-payouts", { hasBody: false }, args),
1041
+ // POST /payouts/builder-payouts — rank: archon — POST /payouts/builder-payouts
1042
+ postPayoutsBuilderPayouts: (args) => request("POST", "/payouts/builder-payouts", { hasBody: true }, args),
1039
1043
  // POST /payouts/contracts — rank: archon — POST /payouts/contracts
1040
1044
  postPayoutsContracts: (args) => request("POST", "/payouts/contracts", { hasBody: true }, args),
1041
1045
  // POST /payouts/freezes — rank: archon — POST /payouts/freezes
@@ -144,6 +144,7 @@ export interface GetPageNotesSiteResponse { notes: unknown }
144
144
  export interface GetPayTermsResponse { pay_terms: unknown }
145
145
  export interface GetPayTypeGatesResponse { gates: unknown }
146
146
  export interface GetPayoutsApprovalsResponse { approvals: unknown }
147
+ export interface GetPayoutsBuilderPayoutsResponse { payouts: unknown; page: PageInfo }
147
148
  export interface GetPayoutsGatesBuilderIdResponse { gate: unknown }
148
149
  export interface GetPayoutsRulesResponse { rules: unknown }
149
150
  export interface GetProfilesHandleResponse { account: unknown; cross_project: unknown }
@@ -534,6 +535,7 @@ export interface PostPayoutsAgeRecordsRequest { builder_id: StringifiableId; tie
534
535
  export interface PostPayoutsAgeRecordsResponse { record: unknown }
535
536
  export interface PostPayoutsApproveRequest { recipient_id?: StringifiableId; amount_cents?: unknown; currency?: unknown; note?: unknown }
536
537
  export interface PostPayoutsApproveResponse { approval: unknown }
538
+ export interface PostPayoutsBuilderPayoutsRequest { approval_id: StringifiableId; task_id: StringifiableId }
537
539
  export interface PostPayoutsFreezesIdDecideRequest { decision: unknown; statement: unknown }
538
540
  export interface PostPayoutsFreezesIdDecideResponse { event: unknown }
539
541
  export interface PostPayoutsFreezesRequest { builder_id: StringifiableId; notice_text: unknown; owed_cents?: unknown }
@@ -1675,6 +1677,10 @@ export interface BongosClient {
1675
1677
  getPayoutsApprovals(args?: RequestArgs): Promise<GetPayoutsApprovalsResponse>;
1676
1678
  /** POST /payouts/approve — rank: archon */
1677
1679
  postPayoutsApprove(args?: RequestArgs & { body?: PostPayoutsApproveRequest }): Promise<PostPayoutsApproveResponse>;
1680
+ /** GET /payouts/builder-payouts — rank: archon */
1681
+ getPayoutsBuilderPayouts(args?: RequestArgs): Promise<GetPayoutsBuilderPayoutsResponse>;
1682
+ /** POST /payouts/builder-payouts — rank: archon */
1683
+ postPayoutsBuilderPayouts(args: RequestArgs & { body: PostPayoutsBuilderPayoutsRequest }): Promise<ApiResponse>;
1678
1684
  /** POST /payouts/contracts — rank: archon */
1679
1685
  postPayoutsContracts(args?: RequestArgs): Promise<ApiResponse>;
1680
1686
  /** POST /payouts/freezes — rank: archon */
@@ -1033,6 +1033,10 @@ export function createClient(opts = {}) {
1033
1033
  getPayoutsApprovals: (args) => request("GET", "/payouts/approvals", { hasBody: false }, args),
1034
1034
  // POST /payouts/approve — rank: archon — POST /payouts/approve
1035
1035
  postPayoutsApprove: (args) => request("POST", "/payouts/approve", { hasBody: true }, args),
1036
+ // GET /payouts/builder-payouts — rank: archon — GET /payouts/builder-payouts
1037
+ getPayoutsBuilderPayouts: (args) => request("GET", "/payouts/builder-payouts", { hasBody: false }, args),
1038
+ // POST /payouts/builder-payouts — rank: archon — POST /payouts/builder-payouts
1039
+ postPayoutsBuilderPayouts: (args) => request("POST", "/payouts/builder-payouts", { hasBody: true }, args),
1036
1040
  // POST /payouts/contracts — rank: archon — POST /payouts/contracts
1037
1041
  postPayoutsContracts: (args) => request("POST", "/payouts/contracts", { hasBody: true }, args),
1038
1042
  // POST /payouts/freezes — rank: archon — POST /payouts/freezes
@@ -19595,6 +19595,90 @@
19595
19595
  ]
19596
19596
  }
19597
19597
  },
19598
+ "/payouts/builder-payouts": {
19599
+ "get": {
19600
+ "operationId": "get_payouts_builder_payouts",
19601
+ "tags": [
19602
+ "payouts"
19603
+ ],
19604
+ "summary": "GET /payouts/builder-payouts",
19605
+ "description": "GET /api/bongos/payouts/builder-payouts — every builder payout and where it stands (task 1003183, M04): paid, or owed with its latest try and the reason in words.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `payout.approve` (all required).",
19606
+ "x-rank": "archon",
19607
+ "x-source": "src/bongos/routes/payout-approvals.js",
19608
+ "x-permissions": [
19609
+ "payout.approve"
19610
+ ],
19611
+ "responses": {
19612
+ "200": {
19613
+ "description": "Success.",
19614
+ "content": {
19615
+ "application/json": {
19616
+ "schema": {
19617
+ "$ref": "#/components/schemas/GetPayoutsBuilderPayoutsResponse"
19618
+ }
19619
+ }
19620
+ }
19621
+ },
19622
+ "400": {
19623
+ "$ref": "#/components/responses/BadRequest"
19624
+ },
19625
+ "401": {
19626
+ "$ref": "#/components/responses/Unauthorized"
19627
+ },
19628
+ "403": {
19629
+ "$ref": "#/components/responses/Forbidden"
19630
+ }
19631
+ },
19632
+ "security": [
19633
+ {
19634
+ "builderSession": []
19635
+ }
19636
+ ]
19637
+ },
19638
+ "post": {
19639
+ "operationId": "post_payouts_builder_payouts",
19640
+ "tags": [
19641
+ "payouts"
19642
+ ],
19643
+ "summary": "POST /payouts/builder-payouts",
19644
+ "description": "POST /api/bongos/payouts/builder-payouts — send ONE approved payout for ONE task (task 1003183, M04). Body: { approval_id, task_id }. The person and the amount come from the approval, never the body. A person presses it on the website: the approval says what may be paid, and this is the person sending it (Art. I). Pressing again is safe: a paid task answers paid, an owed one retries with the same processor key.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `payout.approve` (all required).",
19645
+ "x-rank": "archon",
19646
+ "x-source": "src/bongos/routes/payout-approvals.js",
19647
+ "x-permissions": [
19648
+ "payout.approve"
19649
+ ],
19650
+ "requestBody": {
19651
+ "required": true,
19652
+ "content": {
19653
+ "application/json": {
19654
+ "schema": {
19655
+ "$ref": "#/components/schemas/PostPayoutsBuilderPayoutsRequest"
19656
+ }
19657
+ }
19658
+ },
19659
+ "x-validated": true
19660
+ },
19661
+ "responses": {
19662
+ "200": {
19663
+ "description": "Success."
19664
+ },
19665
+ "400": {
19666
+ "$ref": "#/components/responses/ValidationFailed"
19667
+ },
19668
+ "401": {
19669
+ "$ref": "#/components/responses/Unauthorized"
19670
+ },
19671
+ "403": {
19672
+ "$ref": "#/components/responses/Forbidden"
19673
+ }
19674
+ },
19675
+ "security": [
19676
+ {
19677
+ "builderSession": []
19678
+ }
19679
+ ]
19680
+ }
19681
+ },
19598
19682
  "/payouts/contracts": {
19599
19683
  "post": {
19600
19684
  "operationId": "post_payouts_contracts",
@@ -32569,6 +32653,19 @@
32569
32653
  "approvals"
32570
32654
  ]
32571
32655
  },
32656
+ "GetPayoutsBuilderPayoutsResponse": {
32657
+ "type": "object",
32658
+ "properties": {
32659
+ "payouts": {},
32660
+ "page": {
32661
+ "$ref": "#/components/schemas/PageInfo"
32662
+ }
32663
+ },
32664
+ "required": [
32665
+ "payouts",
32666
+ "page"
32667
+ ]
32668
+ },
32572
32669
  "GetPayoutsGatesBuilderIdResponse": {
32573
32670
  "type": "object",
32574
32671
  "properties": {
@@ -38572,6 +38669,22 @@
38572
38669
  "approval"
38573
38670
  ]
38574
38671
  },
38672
+ "PostPayoutsBuilderPayoutsRequest": {
38673
+ "type": "object",
38674
+ "properties": {
38675
+ "approval_id": {
38676
+ "$ref": "#/components/schemas/StringifiableId"
38677
+ },
38678
+ "task_id": {
38679
+ "$ref": "#/components/schemas/StringifiableId"
38680
+ }
38681
+ },
38682
+ "required": [
38683
+ "approval_id",
38684
+ "task_id"
38685
+ ],
38686
+ "additionalProperties": false
38687
+ },
38575
38688
  "PostPayoutsFreezesIdDecideRequest": {
38576
38689
  "type": "object",
38577
38690
  "properties": {
@@ -41644,9 +41757,9 @@
41644
41757
  "description": "A required dependency/feature is not configured or is temporarily down."
41645
41758
  }
41646
41759
  },
41647
- "x-endpoint-count": 657,
41648
- "x-schema-count": 705,
41760
+ "x-endpoint-count": 659,
41761
+ "x-schema-count": 707,
41649
41762
  "x-undocumented-bodies": 12,
41650
- "x-response-schemas": 451,
41763
+ "x-response-schemas": 452,
41651
41764
  "x-generated-by": "scripts/bongos/gen-api-docs.js"
41652
41765
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Bongos API reference
4
4
 
5
- > **Generated from the live route files** — the route file is authoritative. 657 endpoints across 111 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 659 endpoints across 111 route files.
6
6
  > Machine-readable spec: [`docs/api/openapi.json`](api/openapi.json) (OpenAPI 3.1). Rendered docs site: **`/docs`** (e.g. `cloudbongos.com/docs`).
7
7
 
8
8
  Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust-boundary-server-enforced-permissions.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -708,13 +708,15 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
708
708
  | GET | `/api/bongos/pay-type-gates` | `any-builder` | — | for met/missing (the same pay information `GET /pay-terms` shows, no person's money); the evidence references and who cleared each requir… |
709
709
  | PUT | `/api/bongos/pay-type-gates/:payType/:requirement` | `archon` | `state`, `evidence_ref`, `acknowledged` | .approve (archon floor). |
710
710
 
711
- ## `payouts` (16)
711
+ ## `payouts` (18)
712
712
 
713
713
  | Method | Path | Rank | Body | Description |
714
714
  |---|---|---|---|---|
715
715
  | POST | `/api/bongos/payouts/age-records` | `archon` | `builder_id`, `tier` | POST /api/bongos/payouts/age-records — record a builder's age tier, verified by a person. |
716
716
  | GET | `/api/bongos/payouts/approvals` | `archon` | — | GET /api/bongos/payouts/approvals — the log, newest first. |
717
717
  | POST | `/api/bongos/payouts/approve` | `archon` | `recipient_id`, `amount_cents`, `currency`, `note` | POST /api/bongos/payouts/approve — approve ONE payout. |
718
+ | GET | `/api/bongos/payouts/builder-payouts` | `archon` | — | GET /api/bongos/payouts/builder-payouts — every builder payout and where it stands (task 1003183, M04): paid, or owed with its latest try… |
719
+ | POST | `/api/bongos/payouts/builder-payouts` | `archon` | `approval_id`, `task_id` | POST /api/bongos/payouts/builder-payouts — send ONE approved payout for ONE task (task 1003183, M04). |
718
720
  | POST | `/api/bongos/payouts/contracts` | `archon` | — | POST /api/bongos/payouts/contracts — sign ONE contract. |
719
721
  | POST | `/api/bongos/payouts/freezes` | `archon` | `builder_id`, `notice_text`, `owed_cents` | POST /api/bongos/payouts/freezes — a person freezes a builder's payouts by hand. |
720
722
  | POST | `/api/bongos/payouts/freezes/:id/decide` | `archon` | `decision`, `statement` | POST /api/bongos/payouts/freezes/:id/decide — uphold or lift a freeze, with the reason the person will read. |
@@ -308,6 +308,21 @@ payout_guardian_cosigns(id, builder_id, guardian_id, approval_id | rule_id+run_k
308
308
  -- and a co-signature by anyone but the current guardian.
309
309
  ```
310
310
 
311
+ Builder payouts (migration `core_290`, task 1003183, [ADR 0397](adr/0397-the-payment-rail-is-stripe-connect-with-one-connected-account-per-project.md) D7 — a builder is paid for a task exactly once; `src/bongos/builder-payouts.js`, routes `GET`/`POST /payouts/builder-payouts` gated `payout.approve` plus the person's own web session for the POST; the `payout` movement is booked through the economy module's `economy.account` port in the same transaction. No processor adapter exists yet, so every payout is recorded owed and held `no_processor`):
312
+
313
+ ```
314
+ builder_payouts_owed(id, builder_id FK, task_id FK, approval_id FK payout_approvals,
315
+ amount_cents, currency, recorded_by FK, created_at)
316
+ -- written BEFORE anything is sent; UNIQUE (builder_id, task_id) and UNIQUE
317
+ -- (approval_id): a task is paid once, an approval pays one task.
318
+ builder_payout_attempts(id, owed_id FK, outcome sent|failed|held, processor_ref, reason,
319
+ actor_id, created_at)
320
+ -- at most one `sent` per debt (partial UNIQUE); sent needs processor_ref,
321
+ -- failed/held need a reason. BOTH APPEND-ONLY by trigger. The processor is
322
+ -- called with idempotency key `bongos-payout-<owed id>`, so a retry after an
323
+ -- unknown outcome gets the same transfer back.
324
+ ```
325
+
311
326
  Store sub-categories (migration `core_280`, task 1004355, [ADR 0342](adr/0342-module-categories-are-eight-parents-with-approved-sub-categories.md) D3 — an author proposes one at publish, a Metic+ person approves, renames or merges it; `src/bongos/module-subcategories.js`):
312
327
 
313
328
  ```
@@ -3290,5 +3290,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
3290
3290
  landed since 1.24.15 with no explicit bump. run 41124515103. (task 1002620)
3291
3291
  1.24.17 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
3292
3292
  landed since 1.24.16 with no explicit bump. run 41129472650. (task 1002620)
3293
+ 1.24.18 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
3294
+ landed since 1.24.17 with no explicit bump. run 41131020363. (task 1002620)
3295
+ 1.24.19 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
3296
+ landed since 1.24.18 with no explicit bump. run 41137645458. (task 1002620)
3293
3297
  ---------------------------------------------------------------------------
3294
3298
  ```
@@ -0,0 +1,86 @@
1
+ -- core_290_builder_payouts.sql — a builder is paid for a task, exactly once, and a payout
2
+ -- that did not go through still says it is owed (task 1003183, goal 1000092 M04;
3
+ -- ADR 0385 decisions 1 and 4, ADR 0397 decisions 2, 5 and 7).
4
+ --
5
+ -- TWO TABLES, BOTH APPEND-ONLY.
6
+ --
7
+ -- builder_payouts_owed one row per (builder, task): what is owed, and the
8
+ -- personal approval that authorises it. Written BEFORE
9
+ -- the processor is asked to move anything, in its own
10
+ -- committed step, so a crash, a refusal or a timeout
11
+ -- afterwards still leaves the debt on record. The failure
12
+ -- this exists to prevent is a builder who was silently
13
+ -- never paid, with no trace anything was due.
14
+ -- builder_payout_attempts every try at paying one owed row: sent (with the
15
+ -- processor's transfer reference), failed (with the
16
+ -- reason), or held (not sent, with the reason: a gate,
17
+ -- no processor connected, a missing approval).
18
+ --
19
+ -- EXACTLY ONCE is three rules, each enforced here, not only by the code:
20
+ -- * one owed row per (builder, task), and one per approval (an approval pays one
21
+ -- thing, never two tasks);
22
+ -- * at most one `sent` attempt per owed row;
23
+ -- * the processor is called with an idempotency key derived from the owed row's id,
24
+ -- so a retry after an unknown outcome is answered by the processor with the same
25
+ -- transfer, not a second one.
26
+ --
27
+ -- Amounts are integer cents, as the approval that authorises them is. The money
28
+ -- itself is held by the processor (ADR 0397); the matching `payout` movement is booked
29
+ -- through the economy module's `economy.account` port, in micro-dollars, in the same step as `sent`.
30
+
31
+ CREATE TABLE IF NOT EXISTS builder_payouts_owed (
32
+ id BIGSERIAL PRIMARY KEY,
33
+ builder_id BIGINT NOT NULL REFERENCES builders(id),
34
+ task_id BIGINT NOT NULL REFERENCES tasks(id),
35
+ approval_id BIGINT NOT NULL REFERENCES payout_approvals(id),
36
+ amount_cents BIGINT NOT NULL,
37
+ currency TEXT NOT NULL,
38
+ recorded_by BIGINT NOT NULL REFERENCES builders(id),
39
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
40
+ CONSTRAINT builder_payouts_owed_amount_chk CHECK (amount_cents > 0),
41
+ CONSTRAINT builder_payouts_owed_currency_chk CHECK (currency ~ '^[A-Z]{3}$')
42
+ );
43
+
44
+ -- one payout per builder per task, and one task per approval
45
+ CREATE UNIQUE INDEX IF NOT EXISTS builder_payouts_owed_one_per_task
46
+ ON builder_payouts_owed (builder_id, task_id);
47
+ CREATE UNIQUE INDEX IF NOT EXISTS builder_payouts_owed_one_per_approval
48
+ ON builder_payouts_owed (approval_id);
49
+ CREATE INDEX IF NOT EXISTS builder_payouts_owed_by_time ON builder_payouts_owed (created_at DESC, id DESC);
50
+
51
+ CREATE TABLE IF NOT EXISTS builder_payout_attempts (
52
+ id BIGSERIAL PRIMARY KEY,
53
+ owed_id BIGINT NOT NULL REFERENCES builder_payouts_owed(id),
54
+ outcome TEXT NOT NULL,
55
+ processor_ref TEXT,
56
+ reason TEXT,
57
+ actor_id BIGINT REFERENCES builders(id),
58
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
59
+ CONSTRAINT builder_payout_attempts_outcome_chk CHECK (outcome IN ('sent', 'failed', 'held')),
60
+ CONSTRAINT builder_payout_attempts_reason_len_chk CHECK (reason IS NULL OR length(reason) <= 300),
61
+ -- a sent attempt names the processor transfer; a failed or held one says why
62
+ CONSTRAINT builder_payout_attempts_cause_chk CHECK (
63
+ (outcome = 'sent' AND processor_ref IS NOT NULL) OR
64
+ (outcome IN ('failed', 'held') AND reason IS NOT NULL AND length(reason) > 0))
65
+ );
66
+
67
+ -- paid at most once
68
+ CREATE UNIQUE INDEX IF NOT EXISTS builder_payout_attempts_one_sent
69
+ ON builder_payout_attempts (owed_id) WHERE outcome = 'sent';
70
+ CREATE INDEX IF NOT EXISTS builder_payout_attempts_by_owed ON builder_payout_attempts (owed_id, id DESC);
71
+
72
+ CREATE OR REPLACE FUNCTION builder_payouts_append_only() RETURNS trigger AS $$
73
+ BEGIN
74
+ RAISE EXCEPTION '% is append-only: a payout is never edited or deleted, a new attempt is recorded instead', TG_TABLE_NAME;
75
+ END;
76
+ $$ LANGUAGE plpgsql;
77
+
78
+ DROP TRIGGER IF EXISTS builder_payouts_owed_no_rewrite ON builder_payouts_owed;
79
+ CREATE TRIGGER builder_payouts_owed_no_rewrite BEFORE UPDATE OR DELETE ON builder_payouts_owed
80
+ FOR EACH ROW EXECUTE FUNCTION builder_payouts_append_only();
81
+ DROP TRIGGER IF EXISTS builder_payout_attempts_no_rewrite ON builder_payout_attempts;
82
+ CREATE TRIGGER builder_payout_attempts_no_rewrite BEFORE UPDATE OR DELETE ON builder_payout_attempts
83
+ FOR EACH ROW EXECUTE FUNCTION builder_payouts_append_only();
84
+
85
+ INSERT INTO schema_migrations (version) VALUES ('core_290_builder_payouts')
86
+ ON CONFLICT DO NOTHING;
@@ -8,6 +8,6 @@
8
8
  "default": true,
9
9
  "maintenance": { "status": "core-maintained" },
10
10
  "contributes": { "migrations": true, "routes": ["cost", "credits", "earnings", "leaderboard", "project-account", "reward"] },
11
- "provides": ["reward"],
11
+ "provides": ["reward", "economy.account"],
12
12
  "consumes": []
13
13
  }
@@ -15,11 +15,20 @@
15
15
 
16
16
  const express = require('express');
17
17
  const api = require('../../../src/module-api');
18
- const { readAccount } = require('../project-account');
18
+ const { readAccount, recordMovement } = require('../project-account');
19
19
 
20
20
  const log = api.logger('economy');
21
21
 
22
+ // The `economy.account` PORT (task 1003183): core's payout path (src/bongos/builder-payouts.js)
23
+ // books its `payout` movement through this, inside its own transaction, without importing the
24
+ // module. Registered here for the reason routes/reward.js gives: the loader runs this factory in
25
+ // the live server and whenever a test rebuilds the router. hasProvider-guarded for re-runs.
26
+ function registerSeams() {
27
+ if (!api.hasProvider('economy.account')) api.registerProvider('economy.account', { recordMovement });
28
+ }
29
+
22
30
  module.exports = function buildProjectAccountRouter({ processor = null } = {}) {
31
+ registerSeams();
23
32
  const router = express.Router();
24
33
 
25
34
  // rank: payout.approve (archon floor) — the owner. The account's balance and who was paid what
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.17",
3
+ "version": "1.24.19",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.24.17",
9
+ "version": "1.24.19",
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.24.17",
3
+ "version": "1.24.19",
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",
@@ -10987,5 +10987,17 @@
10987
10987
  "id": "1005029",
10988
10988
  "text": "Artists with both an OpenRouter and a Gemini key saved can now choose which one runs their AI request."
10989
10989
  }
10990
+ ],
10991
+ "1.24.18": [
10992
+ {
10993
+ "id": "1003183",
10994
+ "text": "Builders can now be paid for a task, and never twice. Each payment is written down as owed before anything is sent, so a failed payment still leaves a record. No money moves yet: the Stripe connection comes next."
10995
+ }
10996
+ ],
10997
+ "1.24.19": [
10998
+ {
10999
+ "id": "1005030",
11000
+ "text": "A mockup of the Builders leaderboard now shows the circuit-trace divider from the owner's Studio idea between the column headings and the table. The live page is unchanged."
11001
+ }
10990
11002
  ]
10991
11003
  }