@bongos/core 1.19.485 → 1.19.486
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 +57 -27
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +6 -0
- package/clients/bongos-client/index.cjs +6 -0
- package/clients/bongos-client/index.d.ts +7 -0
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/adr/0232-rot-is-derived-not-swept-and-water-is-the-only-new-verb.md +155 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +147 -3
- package/docs/api-reference.md +7 -4
- package/docs/copy-inventory.md +9 -6
- package/docs/copy-registry.json +34 -7
- package/docs/module-api-changelog.md +2 -0
- package/migrations/core_231_project_settings_and_attention_water.sql +163 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +6 -0
- package/modules/hall-ui/public/goal-inbox.js +119 -1
- package/modules/lifecycle/module.json +2 -1
- package/modules/lifecycle/rot.js +210 -0
- package/modules/lifecycle/routes/rot.js +160 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/fitness.js +9 -0
- package/src/bongos/project-settings.js +193 -0
- package/src/module-api.js +29 -1
- package/tests/module_api.mjs +1 -0
- package/tests/rot_inbox.mjs +532 -0
package/docs/api/openapi.json
CHANGED
|
@@ -6298,6 +6298,51 @@
|
|
|
6298
6298
|
]
|
|
6299
6299
|
}
|
|
6300
6300
|
},
|
|
6301
|
+
"/goals/{id}/water": {
|
|
6302
|
+
"post": {
|
|
6303
|
+
"operationId": "post_goals_id_water",
|
|
6304
|
+
"tags": [
|
|
6305
|
+
"goals"
|
|
6306
|
+
],
|
|
6307
|
+
"summary": "POST /goals/:id/water",
|
|
6308
|
+
"description": "POST /goals/:id/water — reset a rotting goal's clock.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
|
|
6309
|
+
"x-rank": "any-builder",
|
|
6310
|
+
"x-source": "modules/lifecycle/routes/rot.js",
|
|
6311
|
+
"parameters": [
|
|
6312
|
+
{
|
|
6313
|
+
"name": "id",
|
|
6314
|
+
"in": "path",
|
|
6315
|
+
"required": true,
|
|
6316
|
+
"schema": {
|
|
6317
|
+
"type": "string"
|
|
6318
|
+
},
|
|
6319
|
+
"description": "Path parameter `id`."
|
|
6320
|
+
}
|
|
6321
|
+
],
|
|
6322
|
+
"responses": {
|
|
6323
|
+
"200": {
|
|
6324
|
+
"description": "Success."
|
|
6325
|
+
},
|
|
6326
|
+
"400": {
|
|
6327
|
+
"$ref": "#/components/responses/BadRequest"
|
|
6328
|
+
},
|
|
6329
|
+
"401": {
|
|
6330
|
+
"$ref": "#/components/responses/Unauthorized"
|
|
6331
|
+
},
|
|
6332
|
+
"403": {
|
|
6333
|
+
"$ref": "#/components/responses/Forbidden"
|
|
6334
|
+
},
|
|
6335
|
+
"404": {
|
|
6336
|
+
"$ref": "#/components/responses/NotFound"
|
|
6337
|
+
}
|
|
6338
|
+
},
|
|
6339
|
+
"security": [
|
|
6340
|
+
{
|
|
6341
|
+
"builderSession": []
|
|
6342
|
+
}
|
|
6343
|
+
]
|
|
6344
|
+
}
|
|
6345
|
+
},
|
|
6301
6346
|
"/government/assignments": {
|
|
6302
6347
|
"get": {
|
|
6303
6348
|
"operationId": "get_government_assignments",
|
|
@@ -7364,6 +7409,44 @@
|
|
|
7364
7409
|
]
|
|
7365
7410
|
}
|
|
7366
7411
|
},
|
|
7412
|
+
"/inbox/rotting": {
|
|
7413
|
+
"get": {
|
|
7414
|
+
"operationId": "get_inbox_rotting",
|
|
7415
|
+
"tags": [
|
|
7416
|
+
"inbox"
|
|
7417
|
+
],
|
|
7418
|
+
"summary": "GET /inbox/rotting",
|
|
7419
|
+
"description": "GET /inbox/rotting — what is quietly rotting, for this caller. rank: any-builder — own-scoped by default. The builder id comes from the authenticated session and is never read off the request, so a caller can only ever widen the result by HOLDING an atom, never by naming a different builder. A Xenos sees exactly the things they created and nothing else. ?rot_days= is a LENS, not a setting: it answers \"what would 7 days show me?\" without reconfiguring the project, and is never written back. The response reports the timer and where the number came from, so a reader can always tell a lens apart from the project's real answer (the src/stale-timer.js receipt convention — a number with no provenance is what let 6h and 24h coexist).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
|
|
7420
|
+
"x-rank": "any-builder",
|
|
7421
|
+
"x-source": "modules/lifecycle/routes/rot.js",
|
|
7422
|
+
"responses": {
|
|
7423
|
+
"200": {
|
|
7424
|
+
"description": "Success.",
|
|
7425
|
+
"content": {
|
|
7426
|
+
"application/json": {
|
|
7427
|
+
"schema": {
|
|
7428
|
+
"$ref": "#/components/schemas/GetInboxRottingResponse"
|
|
7429
|
+
}
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
},
|
|
7433
|
+
"400": {
|
|
7434
|
+
"$ref": "#/components/responses/BadRequest"
|
|
7435
|
+
},
|
|
7436
|
+
"401": {
|
|
7437
|
+
"$ref": "#/components/responses/Unauthorized"
|
|
7438
|
+
},
|
|
7439
|
+
"403": {
|
|
7440
|
+
"$ref": "#/components/responses/Forbidden"
|
|
7441
|
+
}
|
|
7442
|
+
},
|
|
7443
|
+
"security": [
|
|
7444
|
+
{
|
|
7445
|
+
"builderSession": []
|
|
7446
|
+
}
|
|
7447
|
+
]
|
|
7448
|
+
}
|
|
7449
|
+
},
|
|
7367
7450
|
"/inbox/score": {
|
|
7368
7451
|
"post": {
|
|
7369
7452
|
"operationId": "post_inbox_score",
|
|
@@ -15191,6 +15274,51 @@
|
|
|
15191
15274
|
]
|
|
15192
15275
|
}
|
|
15193
15276
|
},
|
|
15277
|
+
"/tasks/{id}/water": {
|
|
15278
|
+
"post": {
|
|
15279
|
+
"operationId": "post_tasks_id_water",
|
|
15280
|
+
"tags": [
|
|
15281
|
+
"tasks"
|
|
15282
|
+
],
|
|
15283
|
+
"summary": "POST /tasks/:id/water",
|
|
15284
|
+
"description": "POST /tasks/:id/water — reset a rotting task's clock.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
|
|
15285
|
+
"x-rank": "any-builder",
|
|
15286
|
+
"x-source": "modules/lifecycle/routes/rot.js",
|
|
15287
|
+
"parameters": [
|
|
15288
|
+
{
|
|
15289
|
+
"name": "id",
|
|
15290
|
+
"in": "path",
|
|
15291
|
+
"required": true,
|
|
15292
|
+
"schema": {
|
|
15293
|
+
"type": "string"
|
|
15294
|
+
},
|
|
15295
|
+
"description": "Path parameter `id`."
|
|
15296
|
+
}
|
|
15297
|
+
],
|
|
15298
|
+
"responses": {
|
|
15299
|
+
"200": {
|
|
15300
|
+
"description": "Success."
|
|
15301
|
+
},
|
|
15302
|
+
"400": {
|
|
15303
|
+
"$ref": "#/components/responses/BadRequest"
|
|
15304
|
+
},
|
|
15305
|
+
"401": {
|
|
15306
|
+
"$ref": "#/components/responses/Unauthorized"
|
|
15307
|
+
},
|
|
15308
|
+
"403": {
|
|
15309
|
+
"$ref": "#/components/responses/Forbidden"
|
|
15310
|
+
},
|
|
15311
|
+
"404": {
|
|
15312
|
+
"$ref": "#/components/responses/NotFound"
|
|
15313
|
+
}
|
|
15314
|
+
},
|
|
15315
|
+
"security": [
|
|
15316
|
+
{
|
|
15317
|
+
"builderSession": []
|
|
15318
|
+
}
|
|
15319
|
+
]
|
|
15320
|
+
}
|
|
15321
|
+
},
|
|
15194
15322
|
"/versions": {
|
|
15195
15323
|
"get": {
|
|
15196
15324
|
"operationId": "get_versions",
|
|
@@ -16307,6 +16435,22 @@
|
|
|
16307
16435
|
"open_count"
|
|
16308
16436
|
]
|
|
16309
16437
|
},
|
|
16438
|
+
"GetInboxRottingResponse": {
|
|
16439
|
+
"type": "object",
|
|
16440
|
+
"properties": {
|
|
16441
|
+
"rows": {},
|
|
16442
|
+
"count": {},
|
|
16443
|
+
"scope": {},
|
|
16444
|
+
"timer": {},
|
|
16445
|
+
"cutoff": {},
|
|
16446
|
+
"ok": {
|
|
16447
|
+
"type": "boolean"
|
|
16448
|
+
},
|
|
16449
|
+
"tier": {},
|
|
16450
|
+
"id": {},
|
|
16451
|
+
"watered_at": {}
|
|
16452
|
+
}
|
|
16453
|
+
},
|
|
16310
16454
|
"GetInboxSparksResponse": {
|
|
16311
16455
|
"type": "object",
|
|
16312
16456
|
"properties": {
|
|
@@ -21505,9 +21649,9 @@
|
|
|
21505
21649
|
"description": "A required dependency/feature is not configured or is temporarily down."
|
|
21506
21650
|
}
|
|
21507
21651
|
},
|
|
21508
|
-
"x-endpoint-count":
|
|
21509
|
-
"x-schema-count":
|
|
21652
|
+
"x-endpoint-count": 344,
|
|
21653
|
+
"x-schema-count": 375,
|
|
21510
21654
|
"x-undocumented-bodies": 9,
|
|
21511
|
-
"x-response-schemas":
|
|
21655
|
+
"x-response-schemas": 256,
|
|
21512
21656
|
"x-generated-by": "scripts/gds/gen-api-docs.js"
|
|
21513
21657
|
}
|
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. 344 endpoints across 56 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/<redacted>.md)): `public` < `any-builder` < `metic+archon` < `archon`.
|
|
@@ -220,7 +220,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
|
|
|
220
220
|
| GET | `/api/bongos/github/repos` | `any-builder` | — | acts only on the caller's OWN GitHub identity (the token they granted). |
|
|
221
221
|
| POST | `/api/bongos/github/repos` | `any-builder` | `name` | creates a repo in the caller's OWN account. |
|
|
222
222
|
|
|
223
|
-
## `goals` (
|
|
223
|
+
## `goals` (31)
|
|
224
224
|
|
|
225
225
|
| Method | Path | Rank | Body | Description |
|
|
226
226
|
|---|---|---|---|---|
|
|
@@ -250,6 +250,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
|
|
|
250
250
|
| POST | `/api/bongos/goals/:id/tasks` | `any-builder` | `title`, `description`, `touches`, `est_minutes`, `priority`, `kind`, `discipline`, `value_summary`, `parent_task_id` | POST /goals/:id/tasks — bounded task authoring within a goal's scope (BV1.R60 / ADR 0086 §3). |
|
|
251
251
|
| POST | `/api/bongos/goals/:id/transfer` | `any-builder` | `builder_id` | POST /goals/:id/transfer — hand the goal to a new owner (task 1735). |
|
|
252
252
|
| PATCH | `/api/bongos/goals/:id/visibility` | `any-builder` | — | PATCH /goals/:id/visibility — make a goal public\|private (task 1952 / ADR 0112). |
|
|
253
|
+
| POST | `/api/bongos/goals/:id/water` | `any-builder` | — | POST /goals/:id/water — reset a rotting goal's clock. |
|
|
253
254
|
| GET | `/api/bongos/goals/inbox` | `any-builder` | — | GET /goals/inbox — the caller's private-goals inbox (task 1952 / ADR 0112): { invitations: invites addressed to me (accept/decline); join… |
|
|
254
255
|
| POST | `/api/bongos/goals/reorder` | `metic+archon` | `version_id`, `ordered_ids` | POST /goals/reorder — Archon drag-to-reorder: set the priority order of every goal WITHIN one version (task 1760). |
|
|
255
256
|
| GET | `/api/bongos/goals/rollups` | `any-builder` | — | GET /goals/rollups?version= — one small row per goal: readiness counters, the last-activity timestamp, the craft set, and the next claima… |
|
|
@@ -294,7 +295,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
|
|
|
294
295
|
| GET | `/api/bongos/help-requests/for-me` | `any-builder` | — | The addressed read — C01's answer to "and fires a notification". |
|
|
295
296
|
| GET | `/api/bongos/help-requests/mine` | `any-builder` | — | your own asks, so you can settle them. |
|
|
296
297
|
|
|
297
|
-
## `inbox` (
|
|
298
|
+
## `inbox` (16)
|
|
298
299
|
|
|
299
300
|
| Method | Path | Rank | Body | Description |
|
|
300
301
|
|---|---|---|---|---|
|
|
@@ -310,6 +311,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
|
|
|
310
311
|
| DELETE | `/api/bongos/inbox/:id/spark` | `any-builder` | — | Withdraw the Big Idea Spark mark — the reversibility half of R144. |
|
|
311
312
|
| GET | `/api/bongos/inbox/awaiting-nod` | `metic+archon` | — | GET /inbox/awaiting-nod — the NOD QUEUE (task 1003066, BV1.R05). |
|
|
312
313
|
| GET | `/api/bongos/inbox/by-builder/:id` | `any-builder` | — | THE IDEA TRAIL: every idea one builder filed, newest first, with what became of each (task 1003281, goal 1000072, criterion legibility-ac… |
|
|
314
|
+
| GET | `/api/bongos/inbox/rotting` | `any-builder` | — | GET /inbox/rotting — what is quietly rotting, for this caller. |
|
|
313
315
|
| POST | `/api/bongos/inbox/score` | `any-builder` | `field_values`, `template_key` | |
|
|
314
316
|
| GET | `/api/bongos/inbox/sparks` | `any-builder` | — | GET /inbox/sparks — THE SPARK QUEUE (task 1002921 / BV1.R145, goal 1000062). |
|
|
315
317
|
| GET | `/api/bongos/inbox/template` | `any-builder` | — | ----------------------------------------------------------------------- The two reads the hall's Full Idea composer is built from (task 1… |
|
|
@@ -559,7 +561,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
|
|
|
559
561
|
|---|---|---|---|---|
|
|
560
562
|
| GET | `/api/bongos/task-visuals/:name` | `public` | — | the WIDEST path this route can take, declared honestly. |
|
|
561
563
|
|
|
562
|
-
## `tasks` (
|
|
564
|
+
## `tasks` (31)
|
|
563
565
|
|
|
564
566
|
| Method | Path | Rank | Body | Description |
|
|
565
567
|
|---|---|---|---|---|
|
|
@@ -588,6 +590,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
|
|
|
588
590
|
| POST | `/api/bongos/tasks/:id/visual` | `any-builder` | `image_b64`, `content_type`, `alt` | POST /tasks/:id/visual — attach (or replace) this task's ship-time visual. |
|
|
589
591
|
| DELETE | `/api/bongos/tasks/:id/visual` | `any-builder` | — | DELETE /tasks/:id/visual — remove it again. |
|
|
590
592
|
| POST | `/api/bongos/tasks/:id/vote` | `metic+archon` | `vote` | POST /tasks/:id/vote { vote: 1 \| -1 \| 0 } — cast/change/clear a peer vote on a confirmed/shipped task. |
|
|
593
|
+
| POST | `/api/bongos/tasks/:id/water` | `any-builder` | — | POST /tasks/:id/water — reset a rotting task's clock. |
|
|
591
594
|
| GET | `/api/bongos/tasks/claimable` | `any-builder` | — | NOTE: /tasks/claimable must come BEFORE /tasks/:id or Express will route 'claimable' to the :id param. |
|
|
592
595
|
| GET | `/api/bongos/tasks/newcomer-floor` | `any-builder` | — | GET /tasks/newcomer-floor — supply gauge for the newcomer queue (task 614). |
|
|
593
596
|
| POST | `/api/bongos/tasks/newcomer-restock` | `metic+archon` | — | POST /tasks/newcomer-restock (task 1168) — bring every evergreen newcomer chore's standing pool up to its configured floor. |
|
package/docs/copy-inventory.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
> Deterministic on a given tree — regenerate and commit rather than hand-editing.
|
|
5
5
|
> Machine-readable twin: [`copy-registry.json`](copy-registry.json).
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**1579 strings** across 3 surfaces · 1372 distinct pieces of copy · 1579 certain, 0 heuristic · 148 shown in more than one place.
|
|
8
8
|
|
|
9
9
|
## Surfaces
|
|
10
10
|
|
|
11
11
|
| surface | lives at | files | strings |
|
|
12
12
|
|---|---|---|---|
|
|
13
|
-
| `builders-hall` | `modules/hall-ui/public` | 72 |
|
|
13
|
+
| `builders-hall` | `modules/hall-ui/public` | 72 | 1136 |
|
|
14
14
|
| `status-dashboard` | `modules/status-ui/public` | 4 | 98 |
|
|
15
15
|
| `landing` | `modules/public-landing/public` | 5 | 345 |
|
|
16
16
|
|
|
@@ -78,7 +78,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
78
78
|
| `563d29ed86d8` | 2x | Bulk actions | modules/hall-ui/public/goals.html:172, modules/hall-ui/public/work.html:129 |
|
|
79
79
|
| … | | _108 more in the JSON registry_ | |
|
|
80
80
|
|
|
81
|
-
## `builders-hall` —
|
|
81
|
+
## `builders-hall` — 1136 strings
|
|
82
82
|
|
|
83
83
|
| id | conf | text | where |
|
|
84
84
|
|---|---|---|---|
|
|
@@ -421,7 +421,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
421
421
|
| `2ae2114b61db` | certain | Get a free key ↗ | `modules/hall-ui/public/settings.js:1020` |
|
|
422
422
|
| `4794a991de3d` | certain | Getting started | `modules/hall-ui/public/hall-widgets.js:59` |
|
|
423
423
|
| `a28b1a567f1a` | certain | GitHub username | `modules/hall-ui/public/hall-render.js:278` |
|
|
424
|
-
| `79934b879a12` | certain | Give the nod | `modules/hall-ui/public/goal-inbox.js:
|
|
424
|
+
| `79934b879a12` | certain | Give the nod | `modules/hall-ui/public/goal-inbox.js:244` |
|
|
425
425
|
| `9e70797b7e97` | certain | Goal id | `modules/hall-ui/public/goals-render.js:768` |
|
|
426
426
|
| `529460e82058` | certain | Goal invitations to you | `modules/hall-ui/public/goal-inbox.js:113` |
|
|
427
427
|
| `e2a9e33abe60` | certain | Goal tasks | `modules/hall-ui/public/goals.html:136` |
|
|
@@ -551,7 +551,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
551
551
|
| `f14a91b3f625` | certain | Most recent first. Each row is one recorded work session; every id on it opens its record. | `modules/hall-ui/public/sessions.html:56` |
|
|
552
552
|
| `ae84ebe1d735` | certain | Name cannot be blank. | `modules/hall-ui/public/settings.js:830` |
|
|
553
553
|
| `31e91ee6ce03` | certain | Name must be {…} characters or fewer. | `modules/hall-ui/public/settings.js:835` |
|
|
554
|
-
| `7def635421ea` | certain | Needs your attention | `modules/hall-ui/public/goal-inbox.js:
|
|
554
|
+
| `7def635421ea` | certain | Needs your attention | `modules/hall-ui/public/goal-inbox.js:385` |
|
|
555
555
|
| `d427d9dab01c` | certain | New claims are paused: {…} confirmed {…} can't land yet, so {…} reward is pending. Rebase and re-ship, or rele | `modules/hall-ui/public/hall-render.js:604` |
|
|
556
556
|
| `7fcc2583c372` | certain | New custom rank | `modules/hall-ui/public/government.html:81` |
|
|
557
557
|
| `9e06c14d155a` | certain | New here — request access | `modules/hall-ui/public/hall-render.js:278` |
|
|
@@ -1176,6 +1176,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1176
1176
|
| `b3757ba3bb46` | certain | {…} · Stored encrypted; never shown again after saving. | `modules/hall-ui/public/settings.js:1054` |
|
|
1177
1177
|
| `94445e6ed5e8` | certain | {…} · code | `modules/hall-ui/public/pair.js:53` |
|
|
1178
1178
|
| `d73256fbc395` | certain | {…} · who votes, and how it {…} | `modules/hall-ui/public/government.js:1043` |
|
|
1179
|
+
| `cab2a4296aec` | certain | {…} · {…} · {…}{…} | `modules/hall-ui/public/goal-inbox.js:326` |
|
|
1179
1180
|
| `085f93f3f775` | certain | {…} — see all standings | `modules/hall-ui/public/hall-render.js:80` |
|
|
1180
1181
|
| `f75ee96a7511` | certain | {…} — total payout from shipped work. | `modules/hall-ui/public/profile.js:58` |
|
|
1181
1182
|
| `2a2728a4ec4f` | certain | {…}% of tasks complete | `modules/hall-ui/public/roadmap.js:70` |
|
|
@@ -1194,9 +1195,11 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1194
1195
|
| `e5c5e94152b3` | certain | — that's all the tooling you need up front. | `modules/hall-ui/public/hall-render.js:811` |
|
|
1195
1196
|
| `a63451a6db06` | certain | — to start and stop your dev box on your behalf. | `modules/hall-ui/public/pair.js:53` |
|
|
1196
1197
|
| `392afc533191` | certain | — type | `modules/hall-ui/public/hall-render.js:744` |
|
|
1198
|
+
| `ff7514f48a7b` | certain | — untouched {…}+ days | `modules/hall-ui/public/goal-inbox.js:363` |
|
|
1197
1199
|
| `68b547166d48` | certain | — {…} confirmed {…} can't land yet, so {…} reward is pending (it lands on ship). Rebase + re-ship or release { | `modules/hall-ui/public/hall-render.js:488` |
|
|
1198
1200
|
| `5b9fa7cb4fb0` | certain | …and {…} more waiting — | `modules/hall-ui/public/goal-inbox.js:121` |
|
|
1199
|
-
| `b2a04abfead0` | certain | …{…} more awaiting a nod. | `modules/hall-ui/public/goal-inbox.js:
|
|
1201
|
+
| `b2a04abfead0` | certain | …{…} more awaiting a nod. | `modules/hall-ui/public/goal-inbox.js:264` |
|
|
1202
|
+
| `616fb9adf3cf` | certain | …{…} more going quiet. | `modules/hall-ui/public/goal-inbox.js:353` |
|
|
1200
1203
|
| `e35f11bdc5d7` | certain | …{…} more open ideas — triage clears them one at a time. | `modules/hall-ui/public/builders.js:853` |
|
|
1201
1204
|
| `de8fa5223aee` | certain | ‹ Prev | `modules/hall-ui/public/hall-kit.js:71` |
|
|
1202
1205
|
| `d4b84b7fbdeb` | certain | ← All goals | `modules/hall-ui/public/goals.html:80` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"generator": "scripts/gds/copy-inventory.js",
|
|
4
4
|
"goal": 1000074,
|
|
5
5
|
"counts": {
|
|
6
|
-
"strings":
|
|
7
|
-
"unique_ids":
|
|
8
|
-
"certain":
|
|
6
|
+
"strings": 1579,
|
|
7
|
+
"unique_ids": 1372,
|
|
8
|
+
"certain": 1579,
|
|
9
9
|
"heuristic": 0,
|
|
10
10
|
"duplicate_ids": 148
|
|
11
11
|
},
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"builders-hall": {
|
|
14
14
|
"at": "modules/hall-ui/public",
|
|
15
15
|
"files": 72,
|
|
16
|
-
"strings":
|
|
16
|
+
"strings": 1136
|
|
17
17
|
},
|
|
18
18
|
"status-dashboard": {
|
|
19
19
|
"at": "modules/status-ui/public",
|
|
@@ -4635,7 +4635,7 @@
|
|
|
4635
4635
|
"surface": "builders-hall",
|
|
4636
4636
|
"text": "Give the nod",
|
|
4637
4637
|
"file": "modules/hall-ui/public/goal-inbox.js",
|
|
4638
|
-
"line":
|
|
4638
|
+
"line": 244,
|
|
4639
4639
|
"origin": "js-markup",
|
|
4640
4640
|
"confidence": "certain"
|
|
4641
4641
|
},
|
|
@@ -5805,7 +5805,7 @@
|
|
|
5805
5805
|
"surface": "builders-hall",
|
|
5806
5806
|
"text": "Needs your attention",
|
|
5807
5807
|
"file": "modules/hall-ui/public/goal-inbox.js",
|
|
5808
|
-
"line":
|
|
5808
|
+
"line": 385,
|
|
5809
5809
|
"origin": "js-markup",
|
|
5810
5810
|
"confidence": "certain"
|
|
5811
5811
|
},
|
|
@@ -11425,6 +11425,15 @@
|
|
|
11425
11425
|
"origin": "js-markup",
|
|
11426
11426
|
"confidence": "certain"
|
|
11427
11427
|
},
|
|
11428
|
+
{
|
|
11429
|
+
"id": "cab2a4296aec",
|
|
11430
|
+
"surface": "builders-hall",
|
|
11431
|
+
"text": "{…} · {…} · {…}{…}",
|
|
11432
|
+
"file": "modules/hall-ui/public/goal-inbox.js",
|
|
11433
|
+
"line": 326,
|
|
11434
|
+
"origin": "js-markup",
|
|
11435
|
+
"confidence": "certain"
|
|
11436
|
+
},
|
|
11428
11437
|
{
|
|
11429
11438
|
"id": "085f93f3f775",
|
|
11430
11439
|
"surface": "builders-hall",
|
|
@@ -11587,6 +11596,15 @@
|
|
|
11587
11596
|
"origin": "js-markup",
|
|
11588
11597
|
"confidence": "certain"
|
|
11589
11598
|
},
|
|
11599
|
+
{
|
|
11600
|
+
"id": "ff7514f48a7b",
|
|
11601
|
+
"surface": "builders-hall",
|
|
11602
|
+
"text": "— untouched {…}+ days",
|
|
11603
|
+
"file": "modules/hall-ui/public/goal-inbox.js",
|
|
11604
|
+
"line": 363,
|
|
11605
|
+
"origin": "js-markup",
|
|
11606
|
+
"confidence": "certain"
|
|
11607
|
+
},
|
|
11590
11608
|
{
|
|
11591
11609
|
"id": "68b547166d48",
|
|
11592
11610
|
"surface": "builders-hall",
|
|
@@ -11610,7 +11628,16 @@
|
|
|
11610
11628
|
"surface": "builders-hall",
|
|
11611
11629
|
"text": "…{…} more awaiting a nod.",
|
|
11612
11630
|
"file": "modules/hall-ui/public/goal-inbox.js",
|
|
11613
|
-
"line":
|
|
11631
|
+
"line": 264,
|
|
11632
|
+
"origin": "js-markup",
|
|
11633
|
+
"confidence": "certain"
|
|
11634
|
+
},
|
|
11635
|
+
{
|
|
11636
|
+
"id": "616fb9adf3cf",
|
|
11637
|
+
"surface": "builders-hall",
|
|
11638
|
+
"text": "…{…} more going quiet.",
|
|
11639
|
+
"file": "modules/hall-ui/public/goal-inbox.js",
|
|
11640
|
+
"line": 353,
|
|
11614
11641
|
"origin": "js-markup",
|
|
11615
11642
|
"confidence": "certain"
|
|
11616
11643
|
},
|
|
@@ -1407,5 +1407,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1407
1407
|
landed since 1.19.483 with no explicit bump. run 33675143968. (task 1002620)
|
|
1408
1408
|
1.19.485 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1409
1409
|
landed since 1.19.484 with no explicit bump. run 33681828446. (task 1002620)
|
|
1410
|
+
1.19.486 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1411
|
+
landed since 1.19.485 with no explicit bump. run 33682949187. (task 1002620)
|
|
1410
1412
|
---------------------------------------------------------------------------
|
|
1411
1413
|
```
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
-- core_231_project_settings_and_attention_water.sql — the rot clock and the knob
|
|
2
|
+
-- that sets it (task 1003279, goal 1000072, criterion legibility-sort-and-staleness).
|
|
3
|
+
--
|
|
4
|
+
-- THE GAP. Goal 1000072's rotting half asks that "untouched-for-X triggers a
|
|
5
|
+
-- configured action rather than a silent decay". Two things were missing to make
|
|
6
|
+
-- that sentence true, and this migration adds exactly those two:
|
|
7
|
+
--
|
|
8
|
+
-- 1. X had nowhere to live. src/stale-timer.js (task 1003476, ADR 0226) owns the
|
|
9
|
+
-- CLAIM-silence timer — hours, env-configured, and the sweep that ACTS on it
|
|
10
|
+
-- releases someone's claim. The rot timer is a different measurement with a
|
|
11
|
+
-- different unit and a different consequence (days; it asks a human a
|
|
12
|
+
-- question), and task 1003280 requires it be "live, DB-backed" and warns
|
|
13
|
+
-- "do not fork a second store". So: one generic project_settings table, with
|
|
14
|
+
-- the rot timer as its first key.
|
|
15
|
+
--
|
|
16
|
+
-- 2. "Water" had nothing to write. The owner's four verbs are prune, kill,
|
|
17
|
+
-- prioritise and WATER — leave the thing alone and reset its clock. Without
|
|
18
|
+
-- somewhere to record that, watering would have to fake a real edit, and the
|
|
19
|
+
-- same line would come back on the next read; the inbox teaches people to
|
|
20
|
+
-- ignore it within a week. attention_watered_at IS the reset.
|
|
21
|
+
--
|
|
22
|
+
-- WHY A COLUMN AND NOT AN ITEMS TABLE. There is deliberately no `attention_items`
|
|
23
|
+
-- row anywhere in this design. The inbox line is DERIVED on read from the rot clock
|
|
24
|
+
-- (below) vs the timer, which makes "exactly one open item per stale thing, not one
|
|
25
|
+
-- per sweep" true by construction rather than by a de-duplicating sweep that has to
|
|
26
|
+
-- be got right.
|
|
27
|
+
-- Acting on the line (prune/kill/prioritise) changes status and the row stops
|
|
28
|
+
-- matching; watering pushes the clock forward and it stops matching. Nothing to
|
|
29
|
+
-- reconcile, nothing to garbage-collect, and no way to accrete duplicates.
|
|
30
|
+
--
|
|
31
|
+
-- Additive + forward-safe: every column is nullable with no backfill, nothing is
|
|
32
|
+
-- renamed, and no existing reader changes meaning (tests/migrations_forward_safe.mjs).
|
|
33
|
+
|
|
34
|
+
BEGIN;
|
|
35
|
+
|
|
36
|
+
-- ---------------------------------------------------------------------------
|
|
37
|
+
-- 1. project_settings — the instance's live, DB-backed knobs.
|
|
38
|
+
-- ---------------------------------------------------------------------------
|
|
39
|
+
--
|
|
40
|
+
-- Deliberately a generic key/value table rather than one column per knob: task
|
|
41
|
+
-- 1003280 puts five project fundamentals on one page, and a table that grows a
|
|
42
|
+
-- migration per knob would make that page a schema change every time. Values are
|
|
43
|
+
-- stored as TEXT and parsed by a typed accessor at the read edge
|
|
44
|
+
-- (src/bongos/project-settings.js), the same shape src/stale-timer.js already uses
|
|
45
|
+
-- for env values — one parser, one range check, one documented default.
|
|
46
|
+
--
|
|
47
|
+
-- A key that has never been set has NO ROW. Absence means "use the code default",
|
|
48
|
+
-- which is what lets a fresh instance boot correctly with an empty table, and what
|
|
49
|
+
-- lets a settings page distinguish "never configured" from "deliberately set to
|
|
50
|
+
-- the same value the default happens to be".
|
|
51
|
+
CREATE TABLE IF NOT EXISTS project_settings (
|
|
52
|
+
key text PRIMARY KEY,
|
|
53
|
+
value text NOT NULL,
|
|
54
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
55
|
+
updated_by bigint REFERENCES builders(id)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
COMMENT ON TABLE project_settings IS
|
|
59
|
+
'Live, DB-backed per-project knobs (task 1003279). Key/value so task 1003280''s settings page can grow a row without a migration. No row = never configured = use the code default; that absence is meaningful, so do not seed defaults here.';
|
|
60
|
+
COMMENT ON COLUMN project_settings.value IS
|
|
61
|
+
'Stored as text and parsed by a typed accessor at the read edge (src/bongos/project-settings.js). A value that fails its range check is IGNORED with a receipt, never coerced silently — the ADR 0226 posture.';
|
|
62
|
+
COMMENT ON COLUMN project_settings.updated_by IS
|
|
63
|
+
'The builder who last set this knob. NULL = set by a system path with no builder in the request (the goals.created_by convention, migration 160).';
|
|
64
|
+
|
|
65
|
+
-- ---------------------------------------------------------------------------
|
|
66
|
+
-- 2. The water mark, on both tiers that can rot.
|
|
67
|
+
-- ---------------------------------------------------------------------------
|
|
68
|
+
--
|
|
69
|
+
-- NULL = never watered, and the thing's own activity timestamp is the whole clock.
|
|
70
|
+
-- This is why the read expression is a GREATEST and not a bare COALESCE: a real edit
|
|
71
|
+
-- after a watering must move the clock forward again, and a watering must never make
|
|
72
|
+
-- a thing look OLDER than its last genuine touch.
|
|
73
|
+
--
|
|
74
|
+
-- THE ROT CLOCK, AND WHY IT IS SHAPED LIKE THIS:
|
|
75
|
+
--
|
|
76
|
+
-- tasks: GREATEST(updated_at, COALESCE(shipped_at, updated_at),
|
|
77
|
+
-- COALESCE(attention_watered_at, updated_at))
|
|
78
|
+
-- goals: GREATEST(updated_at, COALESCE(attention_watered_at, updated_at))
|
|
79
|
+
--
|
|
80
|
+
-- The first two terms are NOT a new definition of "touched" — they are exactly the
|
|
81
|
+
-- one modules/hall-ui/public/task-lib.js already publishes for the Tasks board and
|
|
82
|
+
-- the Goals page (`taskActivityMs = max(updated_at, shipped_at)`, task 1003278, this
|
|
83
|
+
-- same criterion), which folds in shipped_at because a ship path can stamp it
|
|
84
|
+
-- without touching updated_at. This migration adds a THIRD term to that definition
|
|
85
|
+
-- and nothing else. Had the server invented its own two-term clock, the board and
|
|
86
|
+
-- the inbox would disagree about which rows are stale — which is the 6h-vs-24h
|
|
87
|
+
-- failure of ADR 0226 reappearing one tier up, and the reason the indexes below
|
|
88
|
+
-- spell the expression out in full rather than approximating it.
|
|
89
|
+
-- (Goals carry no shipped_at column, so their clock has two terms, not three.)
|
|
90
|
+
ALTER TABLE tasks
|
|
91
|
+
ADD COLUMN IF NOT EXISTS attention_watered_at timestamptz,
|
|
92
|
+
ADD COLUMN IF NOT EXISTS attention_watered_by bigint REFERENCES builders(id);
|
|
93
|
+
|
|
94
|
+
ALTER TABLE goals
|
|
95
|
+
ADD COLUMN IF NOT EXISTS attention_watered_at timestamptz,
|
|
96
|
+
ADD COLUMN IF NOT EXISTS attention_watered_by bigint REFERENCES builders(id);
|
|
97
|
+
|
|
98
|
+
COMMENT ON COLUMN tasks.attention_watered_at IS
|
|
99
|
+
'When a human last said "leave it, it is fine" about this task rotting (task 1003279). Resets the rot clock without touching the work. NULL = never watered.';
|
|
100
|
+
COMMENT ON COLUMN goals.attention_watered_at IS
|
|
101
|
+
'When a human last said "leave it, it is fine" about this goal rotting (task 1003279). Resets the rot clock without touching the work. NULL = never watered.';
|
|
102
|
+
|
|
103
|
+
-- The rot read is "open things whose clock is older than N days", so the index is
|
|
104
|
+
-- on (status, clock) — status first because it is the equality predicate and it
|
|
105
|
+
-- cuts the table to the open rows before the range scan ever runs.
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_attention_rot
|
|
107
|
+
ON tasks (status, (GREATEST(updated_at,
|
|
108
|
+
COALESCE(shipped_at, updated_at),
|
|
109
|
+
COALESCE(attention_watered_at, updated_at))));
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_goals_attention_rot
|
|
111
|
+
ON goals (status, (GREATEST(updated_at, COALESCE(attention_watered_at, updated_at))));
|
|
112
|
+
|
|
113
|
+
-- ---------------------------------------------------------------------------
|
|
114
|
+
-- 3. Rebuild the two `t.*` views so the new columns are projected.
|
|
115
|
+
-- ---------------------------------------------------------------------------
|
|
116
|
+
--
|
|
117
|
+
-- A Postgres view created with `SELECT t.*` pins its column list at CREATE VIEW
|
|
118
|
+
-- time. core_227's header records six columns that silently never reached the claim
|
|
119
|
+
-- feed exactly this way; bodies below are identical to core_227's (the wildcard
|
|
120
|
+
-- re-expands to every current column).
|
|
121
|
+
|
|
122
|
+
DROP VIEW IF EXISTS claimable_tasks;
|
|
123
|
+
CREATE VIEW claimable_tasks AS
|
|
124
|
+
SELECT t.*,
|
|
125
|
+
pms_calibrated_minutes(t.est_minutes, t.kind) AS est_minutes_calibrated
|
|
126
|
+
FROM tasks t
|
|
127
|
+
WHERE t.status = 'ready'
|
|
128
|
+
AND t.title NOT LIKE '\_\_smoke\_\_%' ESCAPE '\'
|
|
129
|
+
AND NOT EXISTS (
|
|
130
|
+
SELECT 1 FROM task_blockers tb WHERE tb.task_id = t.id
|
|
131
|
+
)
|
|
132
|
+
AND NOT EXISTS (
|
|
133
|
+
SELECT 1 FROM claims c
|
|
134
|
+
JOIN tasks t2 ON t2.id = c.task_id
|
|
135
|
+
WHERE c.released_at IS NULL
|
|
136
|
+
AND t2.touches && t.touches
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
DROP VIEW IF EXISTS tasks_session_fit;
|
|
140
|
+
CREATE VIEW tasks_session_fit AS
|
|
141
|
+
SELECT t.*,
|
|
142
|
+
CASE
|
|
143
|
+
WHEN t.automation_tag = 'overnight-safe' AND COALESCE(t.manual_degree, 5) <= 2
|
|
144
|
+
AND NOT EXISTS (SELECT 1 FROM task_blockers tb WHERE tb.task_id = t.id)
|
|
145
|
+
THEN ARRAY['autonomous','check-in','active']
|
|
146
|
+
WHEN t.automation_tag = 'live-only' OR COALESCE(t.manual_degree, 5) >= 4
|
|
147
|
+
THEN ARRAY['active']
|
|
148
|
+
ELSE ARRAY['check-in','active']
|
|
149
|
+
END AS fits_session_modes,
|
|
150
|
+
pms_calibrated_minutes(t.est_minutes, t.kind) AS est_minutes_calibrated,
|
|
151
|
+
CASE
|
|
152
|
+
WHEN t.credits_reward > 0
|
|
153
|
+
AND pms_calibrated_minutes(t.est_minutes, t.kind) IS NOT NULL
|
|
154
|
+
AND pms_calibrated_minutes(t.est_minutes, t.kind) > 0
|
|
155
|
+
THEN ROUND(t.credits_reward::numeric / pms_calibrated_minutes(t.est_minutes, t.kind), 3)
|
|
156
|
+
ELSE NULL
|
|
157
|
+
END AS credits_per_minute
|
|
158
|
+
FROM tasks t;
|
|
159
|
+
|
|
160
|
+
COMMIT;
|
|
161
|
+
|
|
162
|
+
INSERT INTO schema_migrations (version) VALUES ('core_231_project_settings_and_attention_water')
|
|
163
|
+
ON CONFLICT (version) DO NOTHING;
|
|
@@ -386,6 +386,8 @@ function createClient(opts = {}) {
|
|
|
386
386
|
postGoalsIdTransfer: (args) => request("POST", "/goals/{id}/transfer", { hasBody: true }, args),
|
|
387
387
|
// PATCH /goals/{id}/visibility — rank: any-builder — PATCH /goals/:id/visibility
|
|
388
388
|
patchGoalsIdVisibility: (args) => request("PATCH", "/goals/{id}/visibility", { hasBody: true }, args),
|
|
389
|
+
// POST /goals/{id}/water — rank: any-builder — POST /goals/:id/water
|
|
390
|
+
postGoalsIdWater: (args) => request("POST", "/goals/{id}/water", { hasBody: true }, args),
|
|
389
391
|
// GET /goals/inbox — rank: any-builder — GET /goals/inbox
|
|
390
392
|
getGoalsInbox: (args) => request("GET", "/goals/inbox", { hasBody: false }, args),
|
|
391
393
|
// POST /goals/reorder — rank: metic+archon — POST /goals/reorder
|
|
@@ -466,6 +468,8 @@ function createClient(opts = {}) {
|
|
|
466
468
|
getInboxAwaitingNod: (args) => request("GET", "/inbox/awaiting-nod", { hasBody: false }, args),
|
|
467
469
|
// GET /inbox/by-builder/{id} — rank: any-builder — GET /inbox/by-builder/:id
|
|
468
470
|
getInboxByBuilderId: (args) => request("GET", "/inbox/by-builder/{id}", { hasBody: false }, args),
|
|
471
|
+
// GET /inbox/rotting — rank: any-builder — GET /inbox/rotting
|
|
472
|
+
getInboxRotting: (args) => request("GET", "/inbox/rotting", { hasBody: false }, args),
|
|
469
473
|
// POST /inbox/score — rank: any-builder — POST /inbox/score
|
|
470
474
|
postInboxScore: (args) => request("POST", "/inbox/score", { hasBody: true }, args),
|
|
471
475
|
// GET /inbox/sparks — rank: any-builder — GET /inbox/sparks
|
|
@@ -838,6 +842,8 @@ function createClient(opts = {}) {
|
|
|
838
842
|
postTasksIdVisual: (args) => request("POST", "/tasks/{id}/visual", { hasBody: true }, args),
|
|
839
843
|
// POST /tasks/{id}/vote — rank: metic+archon — POST /tasks/:id/vote
|
|
840
844
|
postTasksIdVote: (args) => request("POST", "/tasks/{id}/vote", { hasBody: true }, args),
|
|
845
|
+
// POST /tasks/{id}/water — rank: any-builder — POST /tasks/:id/water
|
|
846
|
+
postTasksIdWater: (args) => request("POST", "/tasks/{id}/water", { hasBody: true }, args),
|
|
841
847
|
// GET /tasks/claimable — rank: any-builder — GET /tasks/claimable
|
|
842
848
|
getTasksClaimable: (args) => request("GET", "/tasks/claimable", { hasBody: false }, args),
|
|
843
849
|
// GET /tasks/newcomer-floor — rank: any-builder — GET /tasks/newcomer-floor
|