@bongos/core 1.19.936 → 1.19.937
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 +52 -27
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +2 -0
- package/clients/bongos-client/index.cjs +2 -0
- package/clients/bongos-client/index.d.ts +3 -0
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/api/openapi.json +91 -2
- package/docs/api-reference.md +3 -2
- package/docs/module-api-changelog.md +2 -0
- package/modules/government/board.js +31 -0
- package/modules/government/db.js +33 -0
- package/modules/government/migrations/government_018_passed_items_index.sql +31 -0
- package/modules/government/routes/government.js +7 -0
- package/modules/ideas/inbox.js +11 -0
- package/modules/ideas/migrations/ideas_010_goal_ratification.sql +103 -0
- package/modules/ideas/module.json +1 -0
- package/modules/ideas/ratify.js +288 -1
- package/modules/ideas/routes/ratify-goal.js +163 -0
- package/modules/ideas/templates.js +16 -4
- package/modules/lifecycle/goal-from-idea.js +131 -0
- package/modules/lifecycle/lifecycle.js +14 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +1 -1
- package/tests/government_seed.mjs +1 -0
- package/tests/idea_goal_ratification.mjs +553 -0
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.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.937",
|
|
6
|
+
"core_contract": "1.19.937",
|
|
7
|
+
"source_commit": "2aee2eb9e23c44abf42a24b09f9603555ba33673",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-21T05:57:31.197Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 511,
|
|
13
13
|
"agent_docs_stubbed": 26,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2334,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2871,
|
|
20
|
+
"tree_sha256": "026277292d3a56e019a060c711325a482164c64ae62daa9c92ee820321bd0a81",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -347,12 +347,12 @@
|
|
|
347
347
|
{
|
|
348
348
|
"path": "clients/bongos-client/README.md",
|
|
349
349
|
"mode": "0000644",
|
|
350
|
-
"sha256": "
|
|
350
|
+
"sha256": "ce2ce4bd71f9ea04c46e8c1f4e7173a941458162be0e3b32759aa0c5f9d97297"
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
353
|
"path": "clients/bongos-client/bongos-client.global.js",
|
|
354
354
|
"mode": "0000644",
|
|
355
|
-
"sha256": "
|
|
355
|
+
"sha256": "47d36e3b0c228706df44c4a91d5b22bd6005a345c95d8ddda2650bf9b8170242"
|
|
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": "
|
|
365
|
+
"sha256": "5368fb77dc06a2ea22ab2db87ec3ac89a9857388bc12117c31dc327e598f63a1"
|
|
366
366
|
},
|
|
367
367
|
{
|
|
368
368
|
"path": "clients/bongos-client/index.d.ts",
|
|
369
369
|
"mode": "0000644",
|
|
370
|
-
"sha256": "
|
|
370
|
+
"sha256": "5d076131337103c34e8b0e46cd613ae898dfa9edeffa6104617f046eb4f651b0"
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
"path": "clients/bongos-client/index.mjs",
|
|
374
374
|
"mode": "0000644",
|
|
375
|
-
"sha256": "
|
|
375
|
+
"sha256": "2e7178e059cb520cf0509a46151624bb00160cc2cd263582015980576b98482d"
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"path": "clients/bongos-client/package.json",
|
|
@@ -2112,12 +2112,12 @@
|
|
|
2112
2112
|
{
|
|
2113
2113
|
"path": "docs/api-reference.md",
|
|
2114
2114
|
"mode": "0000644",
|
|
2115
|
-
"sha256": "
|
|
2115
|
+
"sha256": "d72a950df3fa37b7834a167d60e621434a0d0806f1a3f298b079d0538254be50"
|
|
2116
2116
|
},
|
|
2117
2117
|
{
|
|
2118
2118
|
"path": "docs/api/openapi.json",
|
|
2119
2119
|
"mode": "0000644",
|
|
2120
|
-
"sha256": "
|
|
2120
|
+
"sha256": "f89f852f211ffee8ccc13f4331fc867837eae6b6ac2a0a24292abc4537aa9591"
|
|
2121
2121
|
},
|
|
2122
2122
|
{
|
|
2123
2123
|
"path": "docs/architecture.md",
|
|
@@ -2677,7 +2677,7 @@
|
|
|
2677
2677
|
{
|
|
2678
2678
|
"path": "docs/module-api-changelog.md",
|
|
2679
2679
|
"mode": "0000644",
|
|
2680
|
-
"sha256": "
|
|
2680
|
+
"sha256": "3fddd5b37bb0a00a12bf88b81992eb2510e0115b8cc7f67c8fd67c51b65ae678"
|
|
2681
2681
|
},
|
|
2682
2682
|
{
|
|
2683
2683
|
"path": "docs/modules-contract.md",
|
|
@@ -4317,7 +4317,7 @@
|
|
|
4317
4317
|
{
|
|
4318
4318
|
"path": "modules/government/board.js",
|
|
4319
4319
|
"mode": "0000644",
|
|
4320
|
-
"sha256": "
|
|
4320
|
+
"sha256": "cce76edcf96a8ece8bb3321f5edb505e0e93acae96babe7169da607fd1888f3b"
|
|
4321
4321
|
},
|
|
4322
4322
|
{
|
|
4323
4323
|
"path": "modules/government/catalog.js",
|
|
@@ -4332,7 +4332,7 @@
|
|
|
4332
4332
|
{
|
|
4333
4333
|
"path": "modules/government/db.js",
|
|
4334
4334
|
"mode": "0000644",
|
|
4335
|
-
"sha256": "
|
|
4335
|
+
"sha256": "dc56a5747bb5275ba372dc297cce585219c649984778a924ce22bab7249889a8"
|
|
4336
4336
|
},
|
|
4337
4337
|
{
|
|
4338
4338
|
"path": "modules/government/membership-predicate.js",
|
|
@@ -4459,6 +4459,11 @@
|
|
|
4459
4459
|
"mode": "0000644",
|
|
4460
4460
|
"sha256": "7603087ac279d05eb2c69527557035c72c3bbb1510c16fdb2230b2e377f0df74"
|
|
4461
4461
|
},
|
|
4462
|
+
{
|
|
4463
|
+
"path": "modules/government/migrations/government_018_passed_items_index.sql",
|
|
4464
|
+
"mode": "0000644",
|
|
4465
|
+
"sha256": "c85b1615c66ae68b630c727faa6ab56358a35dea37a0c2da507d11d3909176fd"
|
|
4466
|
+
},
|
|
4462
4467
|
{
|
|
4463
4468
|
"path": "modules/government/module.json",
|
|
4464
4469
|
"mode": "0000644",
|
|
@@ -4492,7 +4497,7 @@
|
|
|
4492
4497
|
{
|
|
4493
4498
|
"path": "modules/government/routes/government.js",
|
|
4494
4499
|
"mode": "0000644",
|
|
4495
|
-
"sha256": "
|
|
4500
|
+
"sha256": "40c2cd95481690b88a065afad62636ae732845a5dc81f082ebd623f7fb060de4"
|
|
4496
4501
|
},
|
|
4497
4502
|
{
|
|
4498
4503
|
"path": "modules/government/routes/rank-sync.js",
|
|
@@ -5462,7 +5467,7 @@
|
|
|
5462
5467
|
{
|
|
5463
5468
|
"path": "modules/ideas/inbox.js",
|
|
5464
5469
|
"mode": "0000644",
|
|
5465
|
-
"sha256": "
|
|
5470
|
+
"sha256": "da8ac68f553980fef162b7d9fbc85481fd60cd885954cf316894a132f845ef6c"
|
|
5466
5471
|
},
|
|
5467
5472
|
{
|
|
5468
5473
|
"path": "modules/ideas/landing-preview.js",
|
|
@@ -5514,10 +5519,15 @@
|
|
|
5514
5519
|
"mode": "0000644",
|
|
5515
5520
|
"sha256": "53c66f25e685931e73334d6b904f7d3c0f3838a15f160bd5387864ef27836aa7"
|
|
5516
5521
|
},
|
|
5522
|
+
{
|
|
5523
|
+
"path": "modules/ideas/migrations/ideas_010_goal_ratification.sql",
|
|
5524
|
+
"mode": "0000644",
|
|
5525
|
+
"sha256": "7ba109e2f5415daec8b0767ecfabb110fc02d8944f4e6cc0664ca2d205e05480"
|
|
5526
|
+
},
|
|
5517
5527
|
{
|
|
5518
5528
|
"path": "modules/ideas/module.json",
|
|
5519
5529
|
"mode": "0000644",
|
|
5520
|
-
"sha256": "
|
|
5530
|
+
"sha256": "a869f9dec25e003006a495b3fbee45ac99c80b306cec7f16808693d70133e717"
|
|
5521
5531
|
},
|
|
5522
5532
|
{
|
|
5523
5533
|
"path": "modules/ideas/pollers/descent-writer.js",
|
|
@@ -5532,7 +5542,7 @@
|
|
|
5532
5542
|
{
|
|
5533
5543
|
"path": "modules/ideas/ratify.js",
|
|
5534
5544
|
"mode": "0000644",
|
|
5535
|
-
"sha256": "
|
|
5545
|
+
"sha256": "05789550a8e6345f27ac78ccef3ac93a7837e99a6b067871189b1e983b4d374f"
|
|
5536
5546
|
},
|
|
5537
5547
|
{
|
|
5538
5548
|
"path": "modules/ideas/reads.js",
|
|
@@ -5549,6 +5559,11 @@
|
|
|
5549
5559
|
"mode": "0000644",
|
|
5550
5560
|
"sha256": "da91fe0641109b3b8adc0cca44480337f15cbd481b590f42d022e9eaa78654b7"
|
|
5551
5561
|
},
|
|
5562
|
+
{
|
|
5563
|
+
"path": "modules/ideas/routes/ratify-goal.js",
|
|
5564
|
+
"mode": "0000644",
|
|
5565
|
+
"sha256": "92c10dbffef40038dac64ea646372e3fcd1c70c5d2bda1d731ddbdcd508d9181"
|
|
5566
|
+
},
|
|
5552
5567
|
{
|
|
5553
5568
|
"path": "modules/ideas/routing.js",
|
|
5554
5569
|
"mode": "0000644",
|
|
@@ -5562,7 +5577,7 @@
|
|
|
5562
5577
|
{
|
|
5563
5578
|
"path": "modules/ideas/templates.js",
|
|
5564
5579
|
"mode": "0000644",
|
|
5565
|
-
"sha256": "
|
|
5580
|
+
"sha256": "345cbf4d87be780ee98c33042d2ec914b40bceeab6122a67a00a3852580b681b"
|
|
5566
5581
|
},
|
|
5567
5582
|
{
|
|
5568
5583
|
"path": "modules/ideas/trail-descent.js",
|
|
@@ -5769,6 +5784,11 @@
|
|
|
5769
5784
|
"mode": "0000644",
|
|
5770
5785
|
"sha256": "c22a0782ddf7a93deb40f700a2afab15a313925647bbdf424db777da5aa29aa1"
|
|
5771
5786
|
},
|
|
5787
|
+
{
|
|
5788
|
+
"path": "modules/lifecycle/goal-from-idea.js",
|
|
5789
|
+
"mode": "0000644",
|
|
5790
|
+
"sha256": "21d091ef596bc67f08a4f0785d17eaddf47d2da702219ccd5af6164413944428"
|
|
5791
|
+
},
|
|
5772
5792
|
{
|
|
5773
5793
|
"path": "modules/lifecycle/goal-rollup.js",
|
|
5774
5794
|
"mode": "0000644",
|
|
@@ -5802,7 +5822,7 @@
|
|
|
5802
5822
|
{
|
|
5803
5823
|
"path": "modules/lifecycle/lifecycle.js",
|
|
5804
5824
|
"mode": "0000644",
|
|
5805
|
-
"sha256": "
|
|
5825
|
+
"sha256": "74e09c7d1a978da826f99cff9e863b1051ab19a6437ae398a1e83ec8293e794f"
|
|
5806
5826
|
},
|
|
5807
5827
|
{
|
|
5808
5828
|
"path": "modules/lifecycle/merge-lock.js",
|
|
@@ -7982,12 +8002,12 @@
|
|
|
7982
8002
|
{
|
|
7983
8003
|
"path": "package-lock.json",
|
|
7984
8004
|
"mode": "0000644",
|
|
7985
|
-
"sha256": "
|
|
8005
|
+
"sha256": "f1999bdf0489eddf32aabd9a5d2aec6b82bd9765a598e0eff299c31a367b6ff6"
|
|
7986
8006
|
},
|
|
7987
8007
|
{
|
|
7988
8008
|
"path": "package.json",
|
|
7989
8009
|
"mode": "0000644",
|
|
7990
|
-
"sha256": "
|
|
8010
|
+
"sha256": "0be6855a6ff73d2592bff19899727f708abd44265f2ea4538cc48491982a5aac"
|
|
7991
8011
|
},
|
|
7992
8012
|
{
|
|
7993
8013
|
"path": "public-docs/index.html",
|
|
@@ -9987,7 +10007,7 @@
|
|
|
9987
10007
|
{
|
|
9988
10008
|
"path": "src/module-api.js",
|
|
9989
10009
|
"mode": "0000644",
|
|
9990
|
-
"sha256": "
|
|
10010
|
+
"sha256": "546941331565d646b5b815a2a66c4833993abd3affcd2ba309ddad87191d766a"
|
|
9991
10011
|
},
|
|
9992
10012
|
{
|
|
9993
10013
|
"path": "src/module-loader/catalog.js",
|
|
@@ -11687,7 +11707,7 @@
|
|
|
11687
11707
|
{
|
|
11688
11708
|
"path": "tests/government_seed.mjs",
|
|
11689
11709
|
"mode": "0000644",
|
|
11690
|
-
"sha256": "
|
|
11710
|
+
"sha256": "e165fe5c67ee4e80c58f489514ac77ba34e51984dabd2329ecdd70052b81a9cc"
|
|
11691
11711
|
},
|
|
11692
11712
|
{
|
|
11693
11713
|
"path": "tests/government_session_scope.mjs",
|
|
@@ -12064,6 +12084,11 @@
|
|
|
12064
12084
|
"mode": "0000644",
|
|
12065
12085
|
"sha256": "63afe2afd59ff64e290234a0cc8d33a0f77b784d8c10c2d7147fe2ab3c114cd1"
|
|
12066
12086
|
},
|
|
12087
|
+
{
|
|
12088
|
+
"path": "tests/idea_goal_ratification.mjs",
|
|
12089
|
+
"mode": "0000644",
|
|
12090
|
+
"sha256": "3c624db8e11ae02f503d19c6b2556b286d3ca59229daacd6ea2319782530c84f"
|
|
12091
|
+
},
|
|
12067
12092
|
{
|
|
12068
12093
|
"path": "tests/idea_governance_pass_credit.mjs",
|
|
12069
12094
|
"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
|
-
-
|
|
8
|
+
- 404 operations across 61 resource groups
|
|
9
9
|
|
|
10
10
|
## Use it from your project
|
|
11
11
|
|
|
@@ -511,6 +511,8 @@ function createClient(opts = {}) {
|
|
|
511
511
|
postInboxIdDevelop: (args) => request("POST", "/inbox/{id}/develop", { hasBody: true }, args),
|
|
512
512
|
// POST /inbox/{id}/ratify — rank: metic+archon — POST /inbox/:id/ratify
|
|
513
513
|
postInboxIdRatify: (args) => request("POST", "/inbox/{id}/ratify", { hasBody: true }, args),
|
|
514
|
+
// POST /inbox/{id}/ratify-goal — rank: metic+archon — POST /inbox/:id/ratify-goal
|
|
515
|
+
postInboxIdRatifyGoal: (args) => request("POST", "/inbox/{id}/ratify-goal", { hasBody: true }, args),
|
|
514
516
|
// POST /inbox/{id}/resubmit — rank: any-builder — POST /inbox/:id/resubmit
|
|
515
517
|
postInboxIdResubmit: (args) => request("POST", "/inbox/{id}/resubmit", { hasBody: true }, args),
|
|
516
518
|
// DELETE /inbox/{id}/spark — rank: any-builder — DELETE /inbox/:id/spark
|
|
@@ -510,6 +510,8 @@ function createClient(opts = {}) {
|
|
|
510
510
|
postInboxIdDevelop: (args) => request("POST", "/inbox/{id}/develop", { hasBody: true }, args),
|
|
511
511
|
// POST /inbox/{id}/ratify — rank: metic+archon — POST /inbox/:id/ratify
|
|
512
512
|
postInboxIdRatify: (args) => request("POST", "/inbox/{id}/ratify", { hasBody: true }, args),
|
|
513
|
+
// POST /inbox/{id}/ratify-goal — rank: metic+archon — POST /inbox/:id/ratify-goal
|
|
514
|
+
postInboxIdRatifyGoal: (args) => request("POST", "/inbox/{id}/ratify-goal", { hasBody: true }, args),
|
|
513
515
|
// POST /inbox/{id}/resubmit — rank: any-builder — POST /inbox/:id/resubmit
|
|
514
516
|
postInboxIdResubmit: (args) => request("POST", "/inbox/{id}/resubmit", { hasBody: true }, args),
|
|
515
517
|
// DELETE /inbox/{id}/spark — rank: any-builder — DELETE /inbox/:id/spark
|
|
@@ -323,6 +323,7 @@ export interface PostGovernmentRanksResponse { rank: unknown }
|
|
|
323
323
|
export interface PostHelpRequestsRequest { needs_craft?: string; needs_builder_id?: number; what_is_stuck: string; task_id?: number; goal_id?: number }
|
|
324
324
|
export interface PostHelpRequestsResponse { ok: boolean; help_request: unknown }
|
|
325
325
|
export interface PostInboxIdDevelopRequest { field_values: Record<string, unknown>; template_key?: string; recommendation?: string }
|
|
326
|
+
export interface PostInboxIdRatifyGoalRequest { target_version: string; scope_modules?: string[]; admit_reason?: string; notes_md?: string }
|
|
326
327
|
export interface PostInboxIdRatifyRequest { notes_md?: string }
|
|
327
328
|
export interface PostInboxIdResubmitRequest { field_values: Record<string, unknown>; template_key?: string; recommendation?: string }
|
|
328
329
|
export interface PostInboxIdSparkResponse { idea: unknown; sparked: boolean; unchanged: boolean }
|
|
@@ -886,6 +887,8 @@ export interface BongosClient {
|
|
|
886
887
|
postInboxIdDevelop(args: RequestArgs & { body: PostInboxIdDevelopRequest }): Promise<ApiResponse>;
|
|
887
888
|
/** POST /inbox/{id}/ratify — rank: metic+archon */
|
|
888
889
|
postInboxIdRatify(args?: RequestArgs & { body?: PostInboxIdRatifyRequest }): Promise<ApiResponse>;
|
|
890
|
+
/** POST /inbox/{id}/ratify-goal — rank: metic+archon */
|
|
891
|
+
postInboxIdRatifyGoal(args: RequestArgs & { body: PostInboxIdRatifyGoalRequest }): Promise<ApiResponse>;
|
|
889
892
|
/** POST /inbox/{id}/resubmit — rank: any-builder */
|
|
890
893
|
postInboxIdResubmit(args: RequestArgs & { body: PostInboxIdResubmitRequest }): Promise<ApiResponse>;
|
|
891
894
|
/** DELETE /inbox/{id}/spark — rank: any-builder */
|
|
@@ -507,6 +507,8 @@ export function createClient(opts = {}) {
|
|
|
507
507
|
postInboxIdDevelop: (args) => request("POST", "/inbox/{id}/develop", { hasBody: true }, args),
|
|
508
508
|
// POST /inbox/{id}/ratify — rank: metic+archon — POST /inbox/:id/ratify
|
|
509
509
|
postInboxIdRatify: (args) => request("POST", "/inbox/{id}/ratify", { hasBody: true }, args),
|
|
510
|
+
// POST /inbox/{id}/ratify-goal — rank: metic+archon — POST /inbox/:id/ratify-goal
|
|
511
|
+
postInboxIdRatifyGoal: (args) => request("POST", "/inbox/{id}/ratify-goal", { hasBody: true }, args),
|
|
510
512
|
// POST /inbox/{id}/resubmit — rank: any-builder — POST /inbox/:id/resubmit
|
|
511
513
|
postInboxIdResubmit: (args) => request("POST", "/inbox/{id}/resubmit", { hasBody: true }, args),
|
|
512
514
|
// DELETE /inbox/{id}/spark — rank: any-builder — DELETE /inbox/:id/spark
|
package/docs/api/openapi.json
CHANGED
|
@@ -8979,6 +8979,65 @@
|
|
|
8979
8979
|
]
|
|
8980
8980
|
}
|
|
8981
8981
|
},
|
|
8982
|
+
"/inbox/{id}/ratify-goal": {
|
|
8983
|
+
"post": {
|
|
8984
|
+
"operationId": "post_inbox_id_ratify_goal",
|
|
8985
|
+
"tags": [
|
|
8986
|
+
"inbox"
|
|
8987
|
+
],
|
|
8988
|
+
"summary": "POST /inbox/:id/ratify-goal",
|
|
8989
|
+
"description": "BV2.R17 (task 1004096, spec R23, goal 1000095) — ratify a FULL IDEA into a GOAL, atomically: - INSERT goals (title from the idea, description = its five answers) - INSERT done_when_criteria on that goal from the \"what does a successful implementation look like\" answer - UPDATE idea_inbox SET status='promoted', reviewed_at=now() - INSERT ideas_goal_ratifications — who ratified, under which board decision, with the author's own recommendation recorded beside it All of it in one transaction; a partial failure rolls back to an open idea. A SEPARATE ROUTE FROM /ratify, not a mode of it. The two take different subjects (a `criterion-proposal` idea whose body_md is JSON vs. a graded Full Idea whose answers are prose), produce different rows, and differ on whether the board has a say. One route with a discriminator would have to document which half of its own body applies, and a caller who got the discriminator wrong would be told about a field rather than about the act. THE SCOPE AND THE VERSION COME FROM THE REQUEST because nothing else can supply them: no prose answer says which version a goal belongs to or which modules it may touch. THE GATES DO NOT come from the request — the handler passes the caller's LIVE rank through to the lifecycle port, which applies every check POST /goals applies (unknown module key, protected scope → Archon, a building version's goal set closed without a named Archon admission). `idea.ratify`'s floor is Metic, so those gates are load-bearing here rather than ceremonial. Statuses: 400 a bad body / an unratifiable idea / an unmappable template · 403 a rank gate · 404 no such idea · 409 the idea is not open, the board has not passed it, the version will not take a goal, or it is already ratified.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `idea.ratify` (all required).",
|
|
8990
|
+
"x-rank": "metic+archon",
|
|
8991
|
+
"x-source": "modules/ideas/routes/ratify-goal.js",
|
|
8992
|
+
"x-permissions": [
|
|
8993
|
+
"idea.ratify"
|
|
8994
|
+
],
|
|
8995
|
+
"parameters": [
|
|
8996
|
+
{
|
|
8997
|
+
"name": "id",
|
|
8998
|
+
"in": "path",
|
|
8999
|
+
"required": true,
|
|
9000
|
+
"schema": {
|
|
9001
|
+
"type": "string"
|
|
9002
|
+
},
|
|
9003
|
+
"description": "Path parameter `id`."
|
|
9004
|
+
}
|
|
9005
|
+
],
|
|
9006
|
+
"requestBody": {
|
|
9007
|
+
"required": true,
|
|
9008
|
+
"content": {
|
|
9009
|
+
"application/json": {
|
|
9010
|
+
"schema": {
|
|
9011
|
+
"$ref": "#/components/schemas/PostInboxIdRatifyGoalRequest"
|
|
9012
|
+
}
|
|
9013
|
+
}
|
|
9014
|
+
},
|
|
9015
|
+
"x-validated": true
|
|
9016
|
+
},
|
|
9017
|
+
"responses": {
|
|
9018
|
+
"200": {
|
|
9019
|
+
"description": "Success."
|
|
9020
|
+
},
|
|
9021
|
+
"400": {
|
|
9022
|
+
"$ref": "#/components/responses/ValidationFailed"
|
|
9023
|
+
},
|
|
9024
|
+
"401": {
|
|
9025
|
+
"$ref": "#/components/responses/Unauthorized"
|
|
9026
|
+
},
|
|
9027
|
+
"403": {
|
|
9028
|
+
"$ref": "#/components/responses/Forbidden"
|
|
9029
|
+
},
|
|
9030
|
+
"404": {
|
|
9031
|
+
"$ref": "#/components/responses/NotFound"
|
|
9032
|
+
}
|
|
9033
|
+
},
|
|
9034
|
+
"security": [
|
|
9035
|
+
{
|
|
9036
|
+
"builderSession": []
|
|
9037
|
+
}
|
|
9038
|
+
]
|
|
9039
|
+
}
|
|
9040
|
+
},
|
|
8982
9041
|
"/inbox/{id}/resubmit": {
|
|
8983
9042
|
"post": {
|
|
8984
9043
|
"operationId": "post_inbox_id_resubmit",
|
|
@@ -23241,6 +23300,36 @@
|
|
|
23241
23300
|
],
|
|
23242
23301
|
"additionalProperties": false
|
|
23243
23302
|
},
|
|
23303
|
+
"PostInboxIdRatifyGoalRequest": {
|
|
23304
|
+
"type": "object",
|
|
23305
|
+
"properties": {
|
|
23306
|
+
"target_version": {
|
|
23307
|
+
"type": "string",
|
|
23308
|
+
"minLength": 1,
|
|
23309
|
+
"maxLength": 64
|
|
23310
|
+
},
|
|
23311
|
+
"scope_modules": {
|
|
23312
|
+
"type": "array",
|
|
23313
|
+
"items": {
|
|
23314
|
+
"type": "string"
|
|
23315
|
+
},
|
|
23316
|
+
"maxItems": 64
|
|
23317
|
+
},
|
|
23318
|
+
"admit_reason": {
|
|
23319
|
+
"type": "string",
|
|
23320
|
+
"minLength": 8,
|
|
23321
|
+
"maxLength": 500
|
|
23322
|
+
},
|
|
23323
|
+
"notes_md": {
|
|
23324
|
+
"type": "string",
|
|
23325
|
+
"maxLength": 10000
|
|
23326
|
+
}
|
|
23327
|
+
},
|
|
23328
|
+
"required": [
|
|
23329
|
+
"target_version"
|
|
23330
|
+
],
|
|
23331
|
+
"additionalProperties": false
|
|
23332
|
+
},
|
|
23244
23333
|
"PostInboxIdRatifyRequest": {
|
|
23245
23334
|
"type": "object",
|
|
23246
23335
|
"properties": {
|
|
@@ -25564,8 +25653,8 @@
|
|
|
25564
25653
|
"description": "A required dependency/feature is not configured or is temporarily down."
|
|
25565
25654
|
}
|
|
25566
25655
|
},
|
|
25567
|
-
"x-endpoint-count":
|
|
25568
|
-
"x-schema-count":
|
|
25656
|
+
"x-endpoint-count": 404,
|
|
25657
|
+
"x-schema-count": 443,
|
|
25569
25658
|
"x-undocumented-bodies": 9,
|
|
25570
25659
|
"x-response-schemas": 301,
|
|
25571
25660
|
"x-generated-by": "scripts/gds/gen-api-docs.js"
|
package/docs/api-reference.md
CHANGED
|
@@ -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.
|
|
5
|
+
> **Generated from the live route files** — the route file is authoritative. 404 endpoints across 66 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`.
|
|
@@ -337,7 +337,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
|
|
|
337
337
|
| GET | `/api/bongos/help-requests/for-me` | `any-builder` | — | The addressed read — C01's answer to "and fires a notification". |
|
|
338
338
|
| GET | `/api/bongos/help-requests/mine` | `any-builder` | — | your own asks, so you can settle them. |
|
|
339
339
|
|
|
340
|
-
## `inbox` (
|
|
340
|
+
## `inbox` (18)
|
|
341
341
|
|
|
342
342
|
| Method | Path | Rank | Body | Description |
|
|
343
343
|
|---|---|---|---|---|
|
|
@@ -348,6 +348,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
|
|
|
348
348
|
| PATCH | `/api/bongos/inbox/:id/body` | `any-builder` | `body_md` | Metic+ (task 360 / ADR 0018): idea triage (promote/discard/merge) shapes the backlog. |
|
|
349
349
|
| POST | `/api/bongos/inbox/:id/develop` | `any-builder` | `field_values`, `template_key`, `recommendation` | POST /inbox/:id/develop — DEVELOP A SPARK INTO A FULL IDEA (task 1002922 / BV1.R146, goal 1000062). |
|
|
350
350
|
| POST | `/api/bongos/inbox/:id/ratify` | `metic+archon` | `notes_md` | V3.R31 (task 252) — Archon ratifies a criterion-proposal idea, atomically: - INSERT done_when_criteria row on the target version - UPDATE… |
|
|
351
|
+
| POST | `/api/bongos/inbox/:id/ratify-goal` | `metic+archon` | `target_version`, `scope_modules`, `admit_reason`, `notes_md` | BV2.R17 (task 1004096, spec R23, goal 1000095) — ratify a FULL IDEA into a GOAL, atomically: - INSERT goals (title from the idea, descrip… |
|
|
351
352
|
| POST | `/api/bongos/inbox/:id/resubmit` | `any-builder` | `field_values`, `template_key`, `recommendation` | RESUBMIT a Full Idea after a rejection (R13 of goal 1000069, criterion C2: an idea never dies and never stalls). |
|
|
352
353
|
| POST | `/api/bongos/inbox/:id/spark` | `any-builder` | — | Mark a Quick Idea as a Big Idea Spark — "I have the spark but not the full picture, someone develop this". |
|
|
353
354
|
| DELETE | `/api/bongos/inbox/:id/spark` | `any-builder` | — | Withdraw the Big Idea Spark mark — the reversibility half of R144. |
|
|
@@ -2346,5 +2346,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2346
2346
|
landed since 1.19.934 with no explicit bump. run 35558269194. (task 1002620)
|
|
2347
2347
|
1.19.936 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2348
2348
|
landed since 1.19.935 with no explicit bump. run 35561285958. (task 1002620)
|
|
2349
|
+
1.19.937 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2350
|
+
landed since 1.19.936 with no explicit bump. run 35566446478. (task 1002620)
|
|
2349
2351
|
---------------------------------------------------------------------------
|
|
2350
2352
|
```
|
|
@@ -1041,6 +1041,36 @@ async function latestRejectionForIdea(ideaId) {
|
|
|
1041
1041
|
});
|
|
1042
1042
|
}
|
|
1043
1043
|
|
|
1044
|
+
// ── BV2.R17's read: did the board CARRY this idea? (task 1004096) ───────────
|
|
1045
|
+
//
|
|
1046
|
+
// The ratification half of the ideator surface turns a Full Idea into a goal,
|
|
1047
|
+
// and spec decision 9 is that the ideator RECOMMENDS while the board DECIDES.
|
|
1048
|
+
// The ideas module holds the author's recommendation on its own grade row, so
|
|
1049
|
+
// without this read "the board decides" would be a sentence in a comment: the
|
|
1050
|
+
// only fact stopping a ratification from being one person's opinion is that a
|
|
1051
|
+
// sitting actually closed `passed`.
|
|
1052
|
+
//
|
|
1053
|
+
// Null means "no passing decision on record", which the caller must treat as a
|
|
1054
|
+
// refusal and never as an absence it may work around. A returned item, an item
|
|
1055
|
+
// still open, and an idea that never reached the board all read the same here,
|
|
1056
|
+
// on purpose — none of them is a mandate, and distinguishing them would invite a
|
|
1057
|
+
// caller to accept one of them.
|
|
1058
|
+
//
|
|
1059
|
+
// Frozen, like latestRejectionForIdea, so a caller cannot decorate the record of
|
|
1060
|
+
// a decision and pass it on as though the board had said more than it did.
|
|
1061
|
+
async function boardPassForIdea(ideaId) {
|
|
1062
|
+
const id = Number(ideaId);
|
|
1063
|
+
if (!Number.isFinite(id) || id <= 0) return null;
|
|
1064
|
+
const row = await db.getLatestPassedItem('full_idea', id);
|
|
1065
|
+
if (!row) return null;
|
|
1066
|
+
return Object.freeze({
|
|
1067
|
+
item_id: row.item_id,
|
|
1068
|
+
outcome: 'passed',
|
|
1069
|
+
opened_at: row.opened_at,
|
|
1070
|
+
closed_at: row.closed_at,
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1044
1074
|
// ── the summons: what is waiting on THIS member's vote (task 1003271) ───────
|
|
1045
1075
|
//
|
|
1046
1076
|
// THE PROBLEM THIS EXISTS TO FIX. Nine items sat open for two days with zero
|
|
@@ -1127,6 +1157,7 @@ module.exports = {
|
|
|
1127
1157
|
closeItem,
|
|
1128
1158
|
maybeCloseAfterVote,
|
|
1129
1159
|
latestRejectionForIdea,
|
|
1160
|
+
boardPassForIdea,
|
|
1130
1161
|
validateProposedConstitution,
|
|
1131
1162
|
proposeAmendment,
|
|
1132
1163
|
boardRoomView,
|
package/modules/government/db.js
CHANGED
|
@@ -610,6 +610,38 @@ async function getLatestReturnedItemWithObjection(subjectType, subjectId) {
|
|
|
610
610
|
return rows[0] || null;
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
// BV2.R17's read (task 1004096): the most recent PASSED item for a subject.
|
|
614
|
+
//
|
|
615
|
+
// The mirror of getLatestReturnedItemWithObjection above, and the reason it
|
|
616
|
+
// exists separately rather than as a `outcome` parameter on that one: the
|
|
617
|
+
// returned read exists to carry an OBJECTION back to an author and joins the
|
|
618
|
+
// votes table to find it, while this one exists to answer a single yes/no —
|
|
619
|
+
// "did the board carry this?" — and must not depend on any vote row existing.
|
|
620
|
+
// A passed item commonly has NO votes at all (a zero-vote sitting passes under
|
|
621
|
+
// the absence rules, ADR 0175 §3), so the LEFT JOIN that is merely defensive
|
|
622
|
+
// there would be load-bearing here, which is a good sign the two are different
|
|
623
|
+
// questions.
|
|
624
|
+
//
|
|
625
|
+
// Ordering is closed_at DESC, id DESC: an idea returned once and resubmitted can
|
|
626
|
+
// have several closed items, and it is the latest decision that stands.
|
|
627
|
+
//
|
|
628
|
+
// Served by the partial index `government_board_items_passed_by_subject`
|
|
629
|
+
// (government_018), the mirror of government_006's index for the returned read.
|
|
630
|
+
// It needs its own: the table only grows, government_003's two indexes both key
|
|
631
|
+
// on OPEN items and government_008's keys on closed_at alone for the whole-board
|
|
632
|
+
// history feed, so none of them helps a lookup filtered by subject.
|
|
633
|
+
async function getLatestPassedItem(subjectType, subjectId) {
|
|
634
|
+
const { rows } = await pool.query(
|
|
635
|
+
`SELECT id AS item_id, closed_at, opened_at, constitution AS decided_under
|
|
636
|
+
FROM government_board_items
|
|
637
|
+
WHERE subject_type = $1 AND subject_id = $2 AND outcome = 'passed'
|
|
638
|
+
ORDER BY closed_at DESC, id DESC
|
|
639
|
+
LIMIT 1`,
|
|
640
|
+
[subjectType, subjectId],
|
|
641
|
+
);
|
|
642
|
+
return rows[0] || null;
|
|
643
|
+
}
|
|
644
|
+
|
|
613
645
|
// The expiry sweep's read (R11): every OPEN item whose deadline has passed, on
|
|
614
646
|
// the database clock, oldest deadline first. Served by the partial index
|
|
615
647
|
// government_board_items_open_by_deadline (government_003 built it for exactly
|
|
@@ -728,6 +760,7 @@ module.exports = {
|
|
|
728
760
|
getIdeaCompleteness,
|
|
729
761
|
getExpiredOpenBoardItems,
|
|
730
762
|
getLatestReturnedItemWithObjection,
|
|
763
|
+
getLatestPassedItem,
|
|
731
764
|
createAmendment,
|
|
732
765
|
getAmendment,
|
|
733
766
|
listOpenBoardItems,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- government_018_passed_items_index.sql — index the passed-item lookup
|
|
2
|
+
-- (task 1004096 / BV2.R17; a grader efficiency finding, and right — exactly as
|
|
3
|
+
-- government_006 was for the sibling read one outcome over).
|
|
4
|
+
--
|
|
5
|
+
-- `getLatestPassedItem` answers "did the board CARRY this subject?" and runs on
|
|
6
|
+
-- every Full-Idea→goal ratification. It is the mirror of
|
|
7
|
+
-- `getLatestReturnedItemWithObjection`, and it inherits that read's problem in
|
|
8
|
+
-- full: `government_board_items` only grows — one row per window, and a
|
|
9
|
+
-- returned idea can be resubmitted without bound — while the table's two
|
|
10
|
+
-- OPEN-item indexes (`government_003`) both key on `closed_at IS NULL` and the
|
|
11
|
+
-- one closed-item index (`government_008`) keys on `closed_at` alone, for the
|
|
12
|
+
-- whole-board history feed. None of them helps a lookup that filters by
|
|
13
|
+
-- subject. Without this, a ratification scans historical volume that scales
|
|
14
|
+
-- with every sitting the project has ever held.
|
|
15
|
+
--
|
|
16
|
+
-- Partial on outcome='passed' — the only outcome this read asks for — and keyed
|
|
17
|
+
-- (subject_type, subject_id, closed_at DESC) to match the query's WHERE and
|
|
18
|
+
-- ORDER BY exactly, the government_006 shape. Two narrow partial indexes rather
|
|
19
|
+
-- than one wider index over `outcome`: each read asks for exactly one outcome
|
|
20
|
+
-- and never ranges across them, so a shared index would be larger and no more
|
|
21
|
+
-- useful to either.
|
|
22
|
+
--
|
|
23
|
+
-- Additive, idempotent, no rows touched — safe on any database state.
|
|
24
|
+
|
|
25
|
+
BEGIN;
|
|
26
|
+
|
|
27
|
+
CREATE INDEX IF NOT EXISTS government_board_items_passed_by_subject
|
|
28
|
+
ON government_board_items (subject_type, subject_id, closed_at DESC)
|
|
29
|
+
WHERE outcome = 'passed';
|
|
30
|
+
|
|
31
|
+
COMMIT;
|
|
@@ -103,6 +103,13 @@ const governmentPort = {
|
|
|
103
103
|
// resubmit path in modules/ideas resolves this to show what was objected to
|
|
104
104
|
// and to check whether the flagged section actually changed.
|
|
105
105
|
latestRejectionForIdea: board.latestRejectionForIdea,
|
|
106
|
+
// BV2.R17 (task 1004096): the record of the board having CARRIED an idea, or
|
|
107
|
+
// null. The ideas module's ratification path resolves this to check the one
|
|
108
|
+
// fact that makes turning a Full Idea into a goal a board decision rather
|
|
109
|
+
// than a ratifier's preference. Read-only, like every other entry here — there
|
|
110
|
+
// is no counterpart that records an outcome, and there must never be one: an
|
|
111
|
+
// outcome is written by a close, never by the module reading it.
|
|
112
|
+
boardPassForIdea: board.boardPassForIdea,
|
|
106
113
|
};
|
|
107
114
|
|
|
108
115
|
function registerSeams() {
|
package/modules/ideas/inbox.js
CHANGED
|
@@ -848,4 +848,15 @@ module.exports = {
|
|
|
848
848
|
parseProposalBody: ratify.parseProposalBody,
|
|
849
849
|
KARMA_RATIFY_DELTA: ratify.KARMA_RATIFY_DELTA,
|
|
850
850
|
KARMA_RATIFY_REASON: ratify.KARMA_RATIFY_REASON,
|
|
851
|
+
// Full-Idea → GOAL ratification, the goal half beside it (task 1004096 /
|
|
852
|
+
// BV2.R17); see ratify.js on why the two halves are not symmetrical.
|
|
853
|
+
//
|
|
854
|
+
// ONLY THE TRANSACTION IS RE-EXPORTED. `composeGoalFromFullIdea` and
|
|
855
|
+
// `GOAL_SHAPE_BY_TEMPLATE` are deliberately NOT on the facade: nothing outside
|
|
856
|
+
// ratify.js calls either, and a re-export no caller needs is an unused export
|
|
857
|
+
// the dead-code ratchet counts. The facade's job is to keep the ~20 callers of
|
|
858
|
+
// the pre-carve surface working, not to publish everything a new file declares
|
|
859
|
+
// — anything that wants the pure composer requires ./ratify directly, as the
|
|
860
|
+
// test does.
|
|
861
|
+
ratifyFullIdeaAsGoal: ratify.ratifyFullIdeaAsGoal,
|
|
851
862
|
};
|