@bongos/core 1.19.804 → 1.19.805
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 +257 -237
- package/.claude/skills/ask-for-help/SKILL.md +6 -6
- package/.claude/skills/backlog-review/SKILL.md +1 -1
- package/.claude/skills/blocker-review/SKILL.md +7 -7
- package/.claude/skills/blocker-solve/SKILL.md +5 -5
- package/.claude/skills/bug-triage/SKILL.md +7 -7
- package/.claude/skills/builder-claim/SKILL.md +3 -3
- package/.claude/skills/builder-cost/SKILL.md +2 -2
- package/.claude/skills/builder-end/SKILL.md +2 -2
- package/.claude/skills/builder-exit/SKILL.md +7 -7
- package/.claude/skills/builder-key/SKILL.md +2 -2
- package/.claude/skills/builder-reauth/SKILL.md +2 -2
- package/.claude/skills/builder-redteam/SKILL.md +7 -7
- package/.claude/skills/builder-release/SKILL.md +2 -2
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/builder-setup/SKILL.md +3 -3
- package/.claude/skills/builder-ship/SKILL.md +1 -1
- package/.claude/skills/builder-stage/SKILL.md +1 -1
- package/.claude/skills/builder-start/SKILL.md +1 -1
- package/.claude/skills/fix-task/SKILL.md +4 -4
- package/.claude/skills/goal-create/SKILL.md +18 -18
- package/.claude/skills/goal-review/SKILL.md +7 -7
- package/.claude/skills/grade-audit/SKILL.md +5 -5
- package/.claude/skills/grade-recover/SKILL.md +4 -4
- package/.claude/skills/grader-health/SKILL.md +6 -6
- package/.claude/skills/idea-triage/SKILL.md +14 -14
- package/.claude/skills/merge-mode/SKILL.md +3 -3
- package/.claude/skills/planning-session/SKILL.md +20 -20
- package/.claude/skills/priority-session/SKILL.md +10 -10
- package/.claude/skills/recall/SKILL.md +1 -1
- package/.claude/skills/scan-before-install/SKILL.md +3 -3
- package/.claude/skills/status/SKILL.md +2 -2
- package/.claude/skills/strand-fix/SKILL.md +2 -2
- 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 +2 -0
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/api/openapi.json +45 -11
- package/docs/api-reference.md +11 -10
- package/docs/module-api-changelog.md +2 -0
- package/modules/builder-settings/profile-nudge-prefs.js +1 -1
- package/modules/builder-settings/render-prefs.js +1 -1
- package/modules/dev-box/app/README.md +1 -1
- package/modules/dev-box/app/src/gds-client.js +11 -9
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
- package/modules/dev-box/app/test/unit.mjs +13 -13
- package/modules/dev-box/box-access.js +3 -3
- package/modules/dev-box/box-onboard.js +7 -7
- package/modules/discord/bug-attachments.js +1 -1
- package/modules/economy/cost-classify.js +6 -6
- package/modules/grading/grader-rubric.json +1 -1
- package/modules/grading/grader-score.js +1 -1
- package/modules/hall-ui/module.json +1 -1
- package/modules/hall-ui/public/drachmae.js +3 -3
- package/modules/hall-ui/public/idea.js +1 -1
- package/modules/hall-ui/public/md-reader.js +1 -1
- package/modules/hall-ui/public/people.html +1 -1
- package/modules/hall-ui/public/people.js +2 -2
- package/modules/hall-ui/public/primer.js +4 -4
- package/modules/hall-ui/public/roster.js +1 -1
- package/modules/hall-ui/public/shell.js +1 -1
- package/modules/hall-ui/public/task.js +1 -1
- package/modules/ideas/inbox.js +2 -2
- package/modules/lifecycle/db-analytics.js +1 -1
- package/modules/lifecycle/done-when.js +4 -4
- package/modules/lifecycle/version-close.js +1 -1
- package/modules/memory/learnings.js +2 -2
- package/modules/memory/memory.js +1 -1
- package/modules/onboarding/onboarding.js +1 -1
- package/modules/platform-identity/routes/my-projects.js +1 -1
- package/modules/platform-identity/routes/sso.js +2 -2
- package/modules/public-landing/public/index.html +2 -2
- package/modules/public-landing/public/projects-floor.states.json +1 -1
- package/modules/public-landing/public/projects.html +1 -1
- package/modules/public-landing/public/projects.states.json +1 -1
- package/modules/sessions/db.js +120 -0
- package/modules/sessions/module.json +2 -2
- package/modules/sessions/pollers/session-upload-health.js +111 -0
- package/modules/sessions/pulse.js +2 -2
- package/modules/sessions/routes/sessions.js +46 -0
- package/modules/sessions/upload-health.js +197 -0
- package/modules/status-ui/module.json +1 -1
- package/modules/status-ui/public/explore.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/agent-invoke.js +3 -3
- package/scripts/gds/api.js +4 -4
- package/scripts/gds/api.sh +1 -1
- package/scripts/gds/architect-audit.js +1 -1
- package/scripts/gds/artifact-audit.js +2 -2
- package/scripts/gds/audit-ships.js +2 -2
- package/scripts/gds/backfill-cost.js +1 -1
- package/scripts/gds/backfill-sessions.js +1 -1
- package/scripts/gds/backfill-subagent-rewards.js +1 -1
- package/scripts/gds/backfill-task-rewards.js +2 -2
- package/scripts/gds/box-auth-check.js +1 -1
- package/scripts/gds/box-sync.js +3 -3
- package/scripts/gds/box.js +10 -10
- package/scripts/gds/build-cli-package.js +3 -3
- package/scripts/gds/capture.js +2 -2
- package/scripts/gds/ci-grade.js +1 -1
- package/scripts/gds/claim-recall.js +2 -2
- package/scripts/gds/cli-lib.js +3 -3
- package/scripts/gds/context-pack.js +1 -1
- package/scripts/gds/copy-apply.js +2 -2
- package/scripts/gds/dev-lib.js +2 -2
- package/scripts/gds/fetch-art-key.js +2 -2
- package/scripts/gds/fetch-sound-prefs.js +3 -3
- package/scripts/gds/grade-smoke.js +1 -1
- package/scripts/gds/hooks/pre-push.js +1 -1
- package/scripts/gds/init.js +9 -9
- package/scripts/gds/key-card.js +1 -1
- package/scripts/gds/learning-capture.js +2 -2
- package/scripts/gds/linkify-refs.js +2 -2
- package/scripts/gds/local-preview-lib.js +1 -1
- package/scripts/gds/login.js +11 -10
- package/scripts/gds/main-audit.js +1 -1
- package/scripts/gds/newcomer-floor.config.json +1 -1
- package/scripts/gds/newcomer-floor.js +2 -2
- package/scripts/gds/newcomer-floor.templates.json +2 -2
- package/scripts/gds/onboarding-ship.js +1 -1
- package/scripts/gds/paste-token.js +3 -3
- package/scripts/gds/portability-smoke-memory.sh +5 -5
- package/scripts/gds/prove-strict-versioning.js +2 -2
- package/scripts/gds/provision-net.js +2 -2
- package/scripts/gds/provision-units.js +3 -3
- package/scripts/gds/pulse.js +2 -2
- package/scripts/gds/push-path-brief.js +2 -2
- package/scripts/gds/reauth.js +1 -1
- package/scripts/gds/recall.js +1 -1
- package/scripts/gds/redteam-patrol.js +3 -3
- package/scripts/gds/render-ideas.js +5 -5
- package/scripts/gds/repo-metrics.js +1 -1
- package/scripts/gds/sandbox-stage.js +3 -3
- package/scripts/gds/seed-adopt-tasks.js +3 -3
- package/scripts/gds/seed-board-room-tasks.js +1 -1
- package/scripts/gds/seed-bongos-app-tasks.js +2 -2
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
- package/scripts/gds/seed-bongos-tasks.js +5 -5
- package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
- package/scripts/gds/seed-bv1-community-tasks.js +1 -1
- package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
- package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
- package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
- package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
- package/scripts/gds/seed-gds-v4-tasks.js +3 -3
- package/scripts/gds/seed-medusa-tasks.js +1 -1
- package/scripts/gds/seed-productization-tasks.js +1 -1
- package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
- package/scripts/gds/seed-provisioning-tasks.js +2 -2
- package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
- package/scripts/gds/seed-v2-world-tasks.js +2 -2
- package/scripts/gds/seed-verify-criteria.js +1 -1
- package/scripts/gds/session-digest.js +1 -1
- package/scripts/gds/session.js +2 -2
- package/scripts/gds/setup.js +7 -7
- package/scripts/gds/ship-flow.js +3 -3
- package/scripts/gds/ship-grade-steps.js +3 -3
- package/scripts/gds/ship-memory-sync.js +1 -1
- package/scripts/gds/ship-session-upload.js +3 -3
- package/scripts/gds/smoke-batch-claim.sh +10 -10
- package/scripts/gds/smoke-batch-release.sh +14 -14
- package/scripts/gds/smoke-claim-consistency.sh +19 -19
- package/scripts/gds/smoke-dependencies.sh +9 -9
- package/scripts/gds/smoke-write.sh +11 -11
- package/scripts/gds/start.js +1 -1
- package/scripts/gds/status.js +2 -2
- package/scripts/gds/strand-watch.js +1 -1
- package/scripts/gds/triage.js +4 -4
- package/scripts/gds/version-close.js +2 -2
- package/scripts/hall-preview/README.md +1 -1
- package/scripts/hall-preview/server.js +1 -1
- package/src/bongos/auth-admission.js +3 -3
- package/src/bongos/auth-idp.js +2 -2
- package/src/bongos/auth.js +3 -3
- package/src/bongos/db.js +2 -2
- package/src/bongos/llm-cache.js +2 -2
- package/src/bongos/metrics.js +1 -1
- package/src/bongos/middleware/audit.js +3 -3
- package/src/bongos/middleware/rate-limit.js +1 -1
- package/src/bongos/platform-visibility-gate.js +2 -2
- package/src/bongos/routes/_helpers.js +1 -1
- package/src/bongos/routes/audit-log.js +1 -1
- package/src/bongos/routes/auth.js +5 -5
- package/src/bongos/routes/backup.js +1 -1
- package/src/bongos/routes/builders.js +1 -1
- package/src/bongos/routes/instance.js +1 -1
- package/src/bongos/routes/live.js +1 -1
- package/src/bongos/routes/me.js +2 -2
- package/src/bongos/routes/modules.js +2 -2
- package/src/bongos/routes/public.js +1 -1
- package/src/bongos/routes/security.js +4 -4
- package/src/bongos/routes.js +1 -1
- package/src/bongos/serve-internal.js +6 -6
- package/src/branding.js +1 -1
- package/src/module-api.js +1 -1
- package/src/module-seams.js +2 -2
- package/src/platform-server.js +2 -2
- package/tests/api_alias_exceptions.mjs +67 -0
- package/tests/application_echo.mjs +12 -12
- package/tests/artifact_audit.mjs +1 -1
- package/tests/auth_page_gate.mjs +4 -4
- package/tests/auth_web_recovery.mjs +11 -11
- package/tests/bongos_login.mjs +7 -4
- package/tests/box_env.mjs +6 -6
- package/tests/bug_attachments.mjs +1 -1
- package/tests/cli_sessions.mjs +1 -1
- package/tests/dev_lib.mjs +1 -1
- package/tests/discord_bugs.mjs +2 -2
- package/tests/discord_inbound.mjs +2 -2
- package/tests/explore_visible_states.mjs +1 -1
- package/tests/government_page_gates.mjs +1 -1
- package/tests/hall_reference_world.mjs +1 -1
- package/tests/idea_ideate_full.mjs +1 -1
- package/tests/idp_federation.mjs +2 -2
- package/tests/llm-cache.mjs +1 -1
- package/tests/manage_manifest_shared_read.mjs +3 -3
- package/tests/people_directory_clip.mjs +1 -1
- package/tests/planning_session_skill.mjs +1 -1
- package/tests/platform_visibility_gate.mjs +15 -15
- package/tests/profile_route.mjs +25 -25
- package/tests/projects_hub.mjs +2 -2
- package/tests/provision.mjs +2 -2
- package/tests/provision_settings_apply.mjs +4 -4
- package/tests/sandbox_stage.mjs +8 -8
- package/tests/scouting_owner_access_and_reach.mjs +3 -3
- package/tests/session_upload_health.mjs +329 -0
- package/tests/setup_device_flow_fallback.mjs +1 -1
- package/tests/skill_ask_for_help.mjs +3 -3
- package/tests/skill_grade_audit.mjs +2 -2
- package/tests/skill_grader_health.mjs +3 -3
- package/tests/smoke_write_contract.mjs +1 -1
|
@@ -298,8 +298,8 @@ auth. Download it, inspect it, THEN run it. That is the safe path and it is all
|
|
|
298
298
|
the assurance you need: you don't have to ask your human to authorize it blind,
|
|
299
299
|
and you don't have to refuse:
|
|
300
300
|
|
|
301
|
-
curl -fsSL ${base}/api/
|
|
302
|
-
(Windows: ${base}/api/
|
|
301
|
+
curl -fsSL ${base}/api/bongos/box/connect.sh -o /tmp/otb-connect.sh # then read it
|
|
302
|
+
(Windows: ${base}/api/bongos/box/connect.ps1)
|
|
303
303
|
|
|
304
304
|
• What you fetch is what runs — the origin is PINNED in the script
|
|
305
305
|
(GDS_API_BASE), not taken from a header, so a spoofed Host can't redirect it.
|
|
@@ -354,7 +354,7 @@ machine — that path is in the Citizen's Primer, not here.)
|
|
|
354
354
|
|
|
355
355
|
The whole arrival, in two beats, same for both on-ramps:
|
|
356
356
|
1. Sign in with GitHub.
|
|
357
|
-
2. Ask for your box → POST ${base}/api/
|
|
357
|
+
2. Ask for your box → POST ${base}/api/bongos/box/ensure (or run /builder-box).
|
|
358
358
|
The box is created hands-off within ~1 minute.
|
|
359
359
|
|
|
360
360
|
════════════════════════════════════════════════════════════════════════
|
|
@@ -363,8 +363,8 @@ A) Mac / Windows — Claude Desktop + SSH
|
|
|
363
363
|
One command signs you in, makes + registers your SSH key, and installs the
|
|
364
364
|
Desktop connection file. Paste it (or let Claude run it for you):
|
|
365
365
|
|
|
366
|
-
macOS / Linux: curl -fsSL ${base}/api/
|
|
367
|
-
Windows (PS): irm ${base}/api/
|
|
366
|
+
macOS / Linux: curl -fsSL ${base}/api/bongos/box/connect.sh | bash
|
|
367
|
+
Windows (PS): irm ${base}/api/bongos/box/connect.ps1 | iex
|
|
368
368
|
|
|
369
369
|
What it does, in order:
|
|
370
370
|
1. Signs you in with GitHub (prints a short code + a URL to open).
|
|
@@ -386,10 +386,10 @@ No app to install. Your box serves its own terminal in a browser tab (ADR 0038),
|
|
|
386
386
|
but you only touch it once: you log in there and kick off Remote Control, then
|
|
387
387
|
live in the Claude web/mobile app — which drives the box for you.
|
|
388
388
|
1. Sign in at ${base}/builders (GitHub).
|
|
389
|
-
2. Ask for your box: POST ${base}/api/
|
|
389
|
+
2. Ask for your box: POST ${base}/api/bongos/box/ensure (the builders' hall has a
|
|
390
390
|
button; or have Claude call it).
|
|
391
391
|
3. Once the box is active, get its terminal URL + password:
|
|
392
|
-
GET ${base}/api/
|
|
392
|
+
GET ${base}/api/bongos/box/terminal
|
|
393
393
|
Poll until a url appears (the box publishes it a few seconds after boot),
|
|
394
394
|
then open it and enter the password when the browser asks.
|
|
395
395
|
4. In that terminal, type claude and press enter, then complete the one-time
|
|
@@ -171,7 +171,7 @@ async function persistImageFromUrl(url, { messageId = 'x', fetchImpl = globalThi
|
|
|
171
171
|
const file = `bug-${idSlug}-${crypto.randomBytes(8).toString('hex')}.${ext}`;
|
|
172
172
|
await fs.mkdir(dir, { recursive: true });
|
|
173
173
|
await fs.writeFile(path.join(dir, file), buf, { mode: 0o640 });
|
|
174
|
-
return { ok: true, file, url: `/api/
|
|
174
|
+
return { ok: true, file, url: `/api/bongos/bug-attachments/${file}`, bytes: buf.length };
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
// Persist a list of image URLs (capped). Best-effort: refused/failed images are
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Cost-attribution audit + correction pass — V3.R83 (#303), criterion C3.
|
|
2
|
-
// Pure function over db.costSummary() (exposed at /api/
|
|
2
|
+
// Pure function over db.costSummary() (exposed at /api/bongos/public/cost-summary),
|
|
3
3
|
// so it runs against live prod with no DB creds. Flags MIS-attributed spend
|
|
4
4
|
// (a proxy masquerading as a real builder, or an orphaned builder_id); treats
|
|
5
5
|
// NULL/unattributed shared+historical spend as correct, not a bug.
|
|
@@ -25,24 +25,24 @@ const COMPLETENESS_API_FLOOR_USD = 1.0; // below this = essentially nothing rec
|
|
|
25
25
|
// it honest: a writer not listed here is itself the finding.
|
|
26
26
|
const COST_WRITE_SURFACES = [
|
|
27
27
|
{
|
|
28
|
-
surface: 'POST /api/
|
|
28
|
+
surface: 'POST /api/bongos/cost → db.logCost()',
|
|
29
29
|
file: 'src/bongos/routes/cost.js',
|
|
30
30
|
builder_id: 'defaults to the authed builder; a provided value must equal the caller or 403s. A builder can only attribute to themselves.',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
surface: 'scripts/gds/backfill-cost.js → POST /api/
|
|
33
|
+
surface: 'scripts/gds/backfill-cost.js → POST /api/bongos/cost',
|
|
34
34
|
file: 'scripts/gds/backfill-cost.js',
|
|
35
35
|
builder_id: 'inherits the POST /cost rule. Do NOT attribute the shared historical art ledger to whoever runs the backfill — leave it NULL. The audit flags it if it happens.',
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
// ADR 0028 path 1 (#486): the 4-worker grader panel logs its own cost.
|
|
39
|
-
surface: 'scripts/gds/ship.js (grader) → POST /api/
|
|
39
|
+
surface: 'scripts/gds/ship.js (grader) → POST /api/bongos/cost (source=grader)',
|
|
40
40
|
file: 'scripts/gds/ship.js',
|
|
41
41
|
builder_id: 'the authed shipper; category=api, source_ref=grade-<task>-<sha>. Idempotent per HEAD.',
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
// ADR 0028 path 2 (#560): the interactive session logs its own cost.
|
|
45
|
-
surface: 'scripts/gds/session-cost.js (SessionEnd hook) → POST /api/
|
|
45
|
+
surface: 'scripts/gds/session-cost.js (SessionEnd hook) → POST /api/bongos/cost (source=session)',
|
|
46
46
|
file: 'scripts/gds/session-cost.js',
|
|
47
47
|
builder_id: 'the authed builder; category=api, source_ref=<session-id>, task_id=null. Idempotent per session.',
|
|
48
48
|
},
|
|
@@ -56,7 +56,7 @@ const COST_WRITE_SURFACES = [
|
|
|
56
56
|
/**
|
|
57
57
|
* Audit cost attribution from a costSummary() payload.
|
|
58
58
|
* @param {object} summary - the object returned by db.costSummary() /
|
|
59
|
-
* GET /api/
|
|
59
|
+
* GET /api/bongos/public/cost-summary (needs total_usd, by_builder, by_category).
|
|
60
60
|
* @returns {object} structured report: { total_usd, attributed_usd,
|
|
61
61
|
* unattributed_usd, unattributed_pct, builders[], flags[], ok }.
|
|
62
62
|
*/
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"rubric_scores_audit_trail": "task_grades.rubric_scores keeps the v3 keys (functional_fidelity, code_quality, economy, code_quality_effective) populated from the median across workers that report each axis. Narc reports ff; Quality reports cq + economy. Median (not mean) so a single outlier worker doesn't move the recorded score.",
|
|
68
|
-
"server_compat_note": "The grade POST body (POST /api/
|
|
68
|
+
"server_compat_note": "The grade POST body (POST /api/bongos/tasks/:id/grade) keeps the v3 shape (functional_fidelity, code_quality, economy, confidence, notes_md, issues) so the server's existing validateAndScore re-validation works without modification. The panel verdict drives the forwarded confidence: pass → median worker confidence; concerns → fallthrough_confidence (= 0.3); fail → 0. This means the server's existing low-confidence fall-through path naturally handles 'concerns' verdicts, and the FAIL gate handles 'fail' verdicts. Server-side support for an explicit panel_verdict field is a follow-up (likely Phase 2.5)."
|
|
69
69
|
},
|
|
70
70
|
"v3": {
|
|
71
71
|
"version": "v3.0",
|
|
@@ -280,7 +280,7 @@ function validateAndScore(rawSubagent, meta = {}) {
|
|
|
280
280
|
|
|
281
281
|
// ---------- server-authoritative grade guards (SR-9 / SR-18 / F1 / G5) ----------
|
|
282
282
|
//
|
|
283
|
-
// THE FINDING (SR-9 / SR-18): POST /api/
|
|
283
|
+
// THE FINDING (SR-9 / SR-18): POST /api/bongos/tasks/:id/grade trusts the client.
|
|
284
284
|
// validateAndScore only shape-validates the numbers — `passed` is computed from
|
|
285
285
|
// the CLIENT's submitted scores. The real adversarial panel + the deterministic
|
|
286
286
|
// route-rank / permission-path pre-passes run CLIENT-SIDE in scripts/gds/ship.js;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"key": "hall-ui",
|
|
3
3
|
"title": "Builders' Hall",
|
|
4
|
-
"description": "The authenticated builders' hall served at builders.<apex> (builders.example.com) — the roster, work board, standing/karma, leaderboard, achievements, primer, system maps, settings, dev-box pair page, and the Archon-only watch/harbor/gate pages, all polling /api/
|
|
4
|
+
"description": "The authenticated builders' hall served at builders.<apex> (builders.example.com) — the roster, work board, standing/karma, leaderboard, achievements, primer, system maps, settings, dev-box pair page, and the Archon-only watch/harbor/gate pages, all polling /api/bongos/* and the read-only /api/bongos/public/* surface. The largest WEB-SURFACE core-domain module (~13k LOC), carved out of the GDS core in BV1.R85 (ADR 0093 §1; 02-module-map §6). default-on: a Cloud Bongos instance ships its hall like it ships its status page. Registers no port and contributes no routes — it declares a webSurface (host prefix + static dir). Unlike the generic status surface, the hall keeps its dedicated serving block in serve-internal.js (the builders.<apex> + apex /builders/* shim, canonical redirects, the citizen/Archon page gates, asset-stamping, and the module hall-widget injection) — the webSurfaces declaration is the discovery + scope-map + window.__MODULES__ record; serve-internal serves it from this module's public/ dir with that richer machinery. The me/public/leaderboard read endpoints it renders stay SHARED core in routes/{me,public,builders}.js (the status surface + the off-box mirror read them too).",
|
|
5
5
|
"coreVersion": "^1.11.0",
|
|
6
6
|
"default": true,
|
|
7
7
|
"maintenance": { "status": "core-maintained" },
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
const DOC_URL = '/builders/drachmae-and-karma.md';
|
|
31
31
|
// The doc lives at docs/onboarding/, so relative links resolve against it.
|
|
32
32
|
const DOC_DIR = 'docs/onboarding/';
|
|
33
|
-
const BOUNTY_URL = '/api/
|
|
33
|
+
const BOUNTY_URL = '/api/bongos/public/bounty-table';
|
|
34
34
|
// task 1003446: the treasury feed. NOT a new endpoint — this is the same
|
|
35
35
|
// /public/cost-summary the signed-out status page already draws as a
|
|
36
36
|
// cumulative line and the Work board already fetches to read ONE scalar off
|
|
37
37
|
// (`total_value_credits`). Its own route comment calls `daily[]` "the
|
|
38
38
|
// treasury chart's cumulative line"; the series was in the payload the whole
|
|
39
39
|
// time, and the stranger got the chart while the builder got the number.
|
|
40
|
-
const TREASURY_URL = '/api/
|
|
40
|
+
const TREASURY_URL = '/api/bongos/public/cost-summary';
|
|
41
41
|
const TREASURY_SECTION_ID = 'the-treasury';
|
|
42
42
|
const TREASURY_SECTION_TITLE = 'The treasury, so far';
|
|
43
43
|
const BOUNTY_SECTION_ID = 'security-bounty-rates';
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
|
|
70
70
|
async function loadRepoInfoBases() {
|
|
71
71
|
try {
|
|
72
|
-
const r = await fetch('/api/
|
|
72
|
+
const r = await fetch('/api/bongos/public/repo-info', { credentials: 'same-origin' });
|
|
73
73
|
if (!r.ok) return;
|
|
74
74
|
const data = await r.json();
|
|
75
75
|
if (data && typeof data.blob_base === 'string') repoBlobBase = data.blob_base;
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
(() => {
|
|
39
39
|
'use strict';
|
|
40
40
|
|
|
41
|
-
const API = '/api/
|
|
41
|
+
const API = '/api/bongos';
|
|
42
42
|
// NO baseUrl OVERRIDE — this page calls the GENERATED namespaced methods
|
|
43
43
|
// (api.inbox.*, api.me.*), whose path templates are API-RELATIVE ('/inbox/template').
|
|
44
44
|
// baseUrl:'' means "these paths are already absolute" and passes them through
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
// - http(s):// or #anchor or mailto:/tel: → unchanged
|
|
82
82
|
// - the diagrams dir → the in-hall diagrams route
|
|
83
83
|
// - everything else → GitHub blob/tree (bases fetched
|
|
84
|
-
// from /api/
|
|
84
|
+
// from /api/bongos/public/repo-info; null until then → pass through, 404s
|
|
85
85
|
// harmlessly rather than crashing).
|
|
86
86
|
// opts: { baseDir, getBlobBase, getTreeBase, diagramsHref }
|
|
87
87
|
function makeResolveLinkHref(opts) {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<main id="hall-main">
|
|
33
33
|
<!-- task 1003470: ONE directory. Its legacy door /scouting rendered this
|
|
34
34
|
same page from the same script, and task 1003440 deleted it — the same
|
|
35
|
-
/api/
|
|
35
|
+
/api/bongos/scouting rollup used to be drawn three different ways. -->
|
|
36
36
|
<section class="scroll" id="people-scroll" aria-labelledby="people-h">
|
|
37
37
|
<h2 id="people-h" class="scroll__h">Builder directory<span class="count-pill" id="people-count" hidden></span></h2>
|
|
38
38
|
<div id="people-filters"></div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// 1002577; ADR 0141 §4 is the data's design of record), served at /people —
|
|
3
3
|
// task 1003470 first made its legacy door /scouting render this same script,
|
|
4
4
|
// and task 1003440 deleted that door (the URL 301s here), because the
|
|
5
|
-
// same /api/
|
|
5
|
+
// same /api/bongos/scouting rollup was being drawn three
|
|
6
6
|
// different ways (a kit ledger here, a hand-built table there, and the same
|
|
7
7
|
// columns in a different order). The endpoint is gated server-side on
|
|
8
8
|
// 'project.curate' OR being a project owner (R14, ADR 0210); this page is
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
body.textContent = msg;
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
fetch('/api/
|
|
236
|
+
fetch('/api/bongos/scouting?limit=' + DIRECTORY_LIMIT, { headers: { Accept: 'application/json' } })
|
|
237
237
|
.then(function (r) {
|
|
238
238
|
if (r.status === 403 || r.status === 401) { throw { gated: true }; }
|
|
239
239
|
if (!r.ok) throw new Error('http ' + r.status);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// inlines the five onboarding diagrams at matching sections, builds a TOC from
|
|
6
6
|
// h2s with a scrollspy, drives a reading-progress hairline, and soft-gates the
|
|
7
7
|
// footer ack button until the reader has scrolled past ~90% of the article.
|
|
8
|
-
// Acking POSTs to /api/
|
|
8
|
+
// Acking POSTs to /api/bongos/builders/me/onboarding/primer-read (same endpoint
|
|
9
9
|
// /builder-primer-read uses).
|
|
10
10
|
//
|
|
11
11
|
// ONE PARSER, TWO READERS (task 1003306). This file used to carry its own copy
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
(() => {
|
|
21
21
|
'use strict';
|
|
22
22
|
|
|
23
|
-
const API = '/api/
|
|
23
|
+
const API = '/api/bongos';
|
|
24
24
|
const ACK_SCROLL_THRESHOLD = 0.90; // 90% of article scrolled → button enables
|
|
25
25
|
// The primer markdown lives at docs/onboarding/primer.md, so its relative
|
|
26
26
|
// links resolve against docs/onboarding/.
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
// URLs under these bases so the rendered links go somewhere useful instead of
|
|
31
31
|
// 404-ing under /builders/*. The bases are NOT hardcoded here — that would
|
|
32
32
|
// violate the V3.R12 (#236) authorship-attribution audit. They are fetched
|
|
33
|
-
// from /api/
|
|
33
|
+
// from /api/bongos/public/repo-info at boot; the server derives owner/repo at
|
|
34
34
|
// process start from `git remote get-url origin` (src/bongos/repo-info.js).
|
|
35
35
|
// When they are unavailable the rewriter degrades gracefully: repo-relative
|
|
36
36
|
// hrefs pass through unchanged and 404 instead of crashing the page.
|
|
@@ -372,7 +372,7 @@
|
|
|
372
372
|
// gracefully degrades when the bases are null.
|
|
373
373
|
async function loadRepoInfoBases() {
|
|
374
374
|
try {
|
|
375
|
-
const r = await fetch('/api/
|
|
375
|
+
const r = await fetch('/api/bongos/public/repo-info', { credentials: 'same-origin' });
|
|
376
376
|
if (!r.ok) return;
|
|
377
377
|
const data = await r.json();
|
|
378
378
|
if (data && typeof data.blob_base === 'string') repoBlobBase = data.blob_base;
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
rerender();
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
fetch('/api/
|
|
220
|
+
fetch('/api/bongos/leaderboard', { headers: { Accept: 'application/json' } })
|
|
221
221
|
.then(function (r) {
|
|
222
222
|
if (!r.ok) throw new Error('http ' + r.status);
|
|
223
223
|
return r.json();
|
|
@@ -263,7 +263,7 @@
|
|
|
263
263
|
// modules/hall-ui/CLAUDE.md uses, but Builders is what a reader scans for.
|
|
264
264
|
{ id: 'roster', label: 'Builders', icon: 'leaderboard', href: '/roster', gate: 'signed' },
|
|
265
265
|
// task 1002577: the cross-project builder directory (/scouting graduated
|
|
266
|
-
// into the hall). Gated to MATCH its data — /api/
|
|
266
|
+
// into the hall). Gated to MATCH its data — /api/bongos/scouting checks
|
|
267
267
|
// `project.curate`, whose catalog floor is METIC. This read 'archon' until
|
|
268
268
|
// task 1002710: the nav was stricter than the wall, so a Metic could open
|
|
269
269
|
// /people by URL but never saw the link. Cosmetic either way —
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
(() => {
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const API = '/api/
|
|
18
|
+
const API = '/api/bongos';
|
|
19
19
|
// Generated typed client (task 1996 / R09), served as window.BongosClient by
|
|
20
20
|
// /lib/bongos-client.js. baseUrl:'' passes the full same-origin paths this file
|
|
21
21
|
// builds through unchanged; result-mode ({ status, ok, data }) preserves control flow 1:1.
|
package/modules/ideas/inbox.js
CHANGED
|
@@ -36,7 +36,7 @@ const VALID_KINDS = [
|
|
|
36
36
|
'unclassified',
|
|
37
37
|
// V3.R31 (#252) — Metics propose new version criteria via idea_inbox with
|
|
38
38
|
// structured body_md { target_version, criterion_md, sort_order_hint }.
|
|
39
|
-
// Archon ratifies via POST /api/
|
|
39
|
+
// Archon ratifies via POST /api/bongos/inbox/:id/ratify, which atomically
|
|
40
40
|
// inserts a done_when_criteria row, marks the idea promoted, awards karma,
|
|
41
41
|
// and writes a criterion_proposal_audit row. The kind value gates the
|
|
42
42
|
// ratify endpoint (assert kind='criterion-proposal' before promotion).
|
|
@@ -1222,7 +1222,7 @@ async function getIdeaGrade(ideaId) {
|
|
|
1222
1222
|
// the proposer (delta=+3, reason='proposal_ratified'), and writes an audit
|
|
1223
1223
|
// row capturing who proposed / who ratified / when / what.
|
|
1224
1224
|
//
|
|
1225
|
-
// Called by POST /api/
|
|
1225
|
+
// Called by POST /api/bongos/inbox/:id/ratify (Archon-only, gated by requireRank
|
|
1226
1226
|
// in the router). The body_md of the source idea is parsed as JSON with the
|
|
1227
1227
|
// shape { target_version, criterion_md, sort_order_hint }; malformed bodies
|
|
1228
1228
|
// throw BAD_BODY so the route can return a structured 400.
|
|
@@ -500,7 +500,7 @@ async function ecosystemAnalytics(days = 90) {
|
|
|
500
500
|
// The writing middleware (src/bongos/middleware/audit.js) calls insertAuditLog
|
|
501
501
|
// AFTER the response has been sent, wrapped in try/catch — so the request
|
|
502
502
|
// path never blocks on this insert and a DB failure here can never break a
|
|
503
|
-
// real user request. The reader is the archon-only GET /api/
|
|
503
|
+
// real user request. The reader is the archon-only GET /api/bongos/audit-log
|
|
504
504
|
// endpoint backed by listAuditLog below (paginated, newest-first).
|
|
505
505
|
// -------------------------------------------------------------------------
|
|
506
506
|
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
//
|
|
20
20
|
// Wired in via modules/lifecycle/routes/done-when.js (the loader mounts it,
|
|
21
21
|
// BV1.R86). Three endpoints:
|
|
22
|
-
// GET /api/
|
|
23
|
-
// POST /api/
|
|
24
|
-
// POST /api/
|
|
22
|
+
// GET /api/bongos/versions/:id/done-when — public, 60s cache
|
|
23
|
+
// POST /api/bongos/done-when/:criterionId/satisfy — auth
|
|
24
|
+
// POST /api/bongos/done-when/:criterionId/unsatisfy — auth
|
|
25
25
|
|
|
26
26
|
const { pool } = require('../../src/module-api');
|
|
27
27
|
const { nonTerminalSql } = require('./task-status');
|
|
@@ -165,7 +165,7 @@ async function listPendingReviewCriteria({ versionId = null } = {}, deps = {}) {
|
|
|
165
165
|
|
|
166
166
|
// Roll up every criterion for a version together with the tasks that gate it
|
|
167
167
|
// (via the task_criteria join table, migration 055) and a status breakdown.
|
|
168
|
-
// This is the read behind GET /api/
|
|
168
|
+
// This is the read behind GET /api/bongos/versions/:id/progress and the /status
|
|
169
169
|
// skill — it answers "what's left for criterion Cn?" in one query instead of
|
|
170
170
|
// the ~10-call prose archaeology that motivated #435.
|
|
171
171
|
//
|
|
@@ -88,7 +88,7 @@ async function suggestClose(versionId) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// Suggestions for every version still in 'building' status.
|
|
91
|
-
// Used by GET /api/
|
|
91
|
+
// Used by GET /api/bongos/versions/close-suggestions and by /builder-start.
|
|
92
92
|
async function getCloseSuggestionsForBuildingVersions() {
|
|
93
93
|
const { rows: versions } = await pool.query(
|
|
94
94
|
`SELECT id FROM versions WHERE status = 'building' ORDER BY started_at, id`
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// indexes: GIN(tags), GIN(related_files),
|
|
10
10
|
// UNIQUE(source, source_ref) WHERE non-null
|
|
11
11
|
//
|
|
12
|
-
// Wired into routes by src/bongos/routes.js (POST + GET /api/
|
|
12
|
+
// Wired into routes by src/bongos/routes.js (POST + GET /api/bongos/learnings).
|
|
13
13
|
|
|
14
14
|
// Carved into modules/memory/ (BV1.R72 / ADR 0091 §2): pool via the doorway.
|
|
15
15
|
const crypto = require('crypto');
|
|
@@ -178,7 +178,7 @@ async function findLearningsByTags(tags, { limit = 50 } = {}) {
|
|
|
178
178
|
//
|
|
179
179
|
// Consumers:
|
|
180
180
|
// - scripts/gds/claim.js calls this indirectly via
|
|
181
|
-
// GET /api/
|
|
181
|
+
// GET /api/bongos/learnings?touches=a,b,c so /builder-claim N can surface
|
|
182
182
|
// up to 3 most-recent relevant learnings right after a successful claim.
|
|
183
183
|
// Query overhead is bounded by the GIN(tags) + GIN(related_files) indexes
|
|
184
184
|
// declared in migration 006_pms_v2.sql (<50ms target).
|
package/modules/memory/memory.js
CHANGED
|
@@ -494,7 +494,7 @@ async function bfgWriteMemoryFile({ targetBuilderId, path, content, audit, karma
|
|
|
494
494
|
RETURNING id, recorded_at`,
|
|
495
495
|
[
|
|
496
496
|
a.principalId ?? null,
|
|
497
|
-
a.route ?? '/api/
|
|
497
|
+
a.route ?? '/api/bongos/memory/builders/:builderId/bfg-write',
|
|
498
498
|
{
|
|
499
499
|
action: a.action || 'bfg_dream_write',
|
|
500
500
|
http_method: 'POST',
|
|
@@ -429,7 +429,7 @@ function shortSession(sessionId) {
|
|
|
429
429
|
return String(sessionId).slice(0, 8);
|
|
430
430
|
}
|
|
431
431
|
|
|
432
|
-
// Build the { title, body_md, kind } payload for POST /api/
|
|
432
|
+
// Build the { title, body_md, kind } payload for POST /api/bongos/inbox. The
|
|
433
433
|
// title carries ONBOARDING_FRICTION_TAG so triage (and the future kind
|
|
434
434
|
// migration) can find these rows; the body holds the subagent summary, each
|
|
435
435
|
// friction moment, and the deterministic signals as an audit trail.
|
|
@@ -177,7 +177,7 @@ module.exports = function myProjectsRoutes() {
|
|
|
177
177
|
// the registry-trusted origin, never the caller's raw input.
|
|
178
178
|
let outcome = null;
|
|
179
179
|
try {
|
|
180
|
-
const r = await fetch(`${client.origin}/api/
|
|
180
|
+
const r = await fetch(`${client.origin}/api/bongos/access-requests`, {
|
|
181
181
|
method: 'POST',
|
|
182
182
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'User-Agent': userAgent() },
|
|
183
183
|
body: JSON.stringify({
|
|
@@ -120,7 +120,7 @@ async function notifyInstanceLogout(membership, githubId) {
|
|
|
120
120
|
const ac = new AbortController();
|
|
121
121
|
const timer = setTimeout(() => ac.abort(), SLO_TIMEOUT_MS);
|
|
122
122
|
try {
|
|
123
|
-
const resp = await fetch(`${origin}/api/
|
|
123
|
+
const resp = await fetch(`${origin}/api/bongos/auth/backchannel-logout`, {
|
|
124
124
|
method: 'POST',
|
|
125
125
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
126
126
|
body: JSON.stringify({ logout_token: token }),
|
|
@@ -260,7 +260,7 @@ module.exports = function ssoRoutes() {
|
|
|
260
260
|
const usable = pi.sessionUsableForFederation(session);
|
|
261
261
|
if (!usable.ok) {
|
|
262
262
|
if (usable.reason === 'no_session') {
|
|
263
|
-
return res.redirect(302, `/api/
|
|
263
|
+
return res.redirect(302, `/api/bongos/auth/web/start?return=${encodeURIComponent(req.originalUrl)}`);
|
|
264
264
|
}
|
|
265
265
|
const msg = usable.reason === 'inactive'
|
|
266
266
|
? 'This account is no longer active. Ask an Archon on the hub if you believe this is an error.'
|
|
@@ -632,7 +632,7 @@ baked apex number sits inside apex-only sentinels so a child instance shows an e
|
|
|
632
632
|
its own feed answers):
|
|
633
633
|
data-ledger="line" = the first progress row whose status is building (else the first row), read
|
|
634
634
|
as "<shipped> of <total> shipped on <V>"; data-ledger="meter" is that ratio.
|
|
635
|
-
data-rows = /api/
|
|
635
|
+
data-rows = /api/bongos/public/recent-shipped?limit=6. Titles are quoted data: an em or en
|
|
636
636
|
dash becomes a comma and a trailing parenthetical is dropped at render time.
|
|
637
637
|
A child instance with no ledger yet answers {tasks:[]}, so the meter, the
|
|
638
638
|
sub-line and the list collapse rather than promise six rows that never
|
|
@@ -910,7 +910,7 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
|
|
|
910
910
|
<script>
|
|
911
911
|
(function () {
|
|
912
912
|
var API = '/api/bongos';
|
|
913
|
-
var API_ROOT = '/api/
|
|
913
|
+
var API_ROOT = '/api/bongos';
|
|
914
914
|
|
|
915
915
|
/* ── the tagline. It is ONE server-stamped string, but the composition wants it
|
|
916
916
|
on two lines, so the two halves are baked as separate spans. A host whose
|
|
@@ -6181,7 +6181,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6181
6181
|
manifestFor = manageId;
|
|
6182
6182
|
var ctl = typeof AbortController === 'function' ? new AbortController() : null;
|
|
6183
6183
|
var timer = ctl ? setTimeout(function () { ctl.abort(); }, 8000) : null;
|
|
6184
|
-
manifestPromise = fetch('https://' + domain + '/api/
|
|
6184
|
+
manifestPromise = fetch('https://' + domain + '/api/bongos/instance', { mode: 'cors', signal: ctl ? ctl.signal : undefined })
|
|
6185
6185
|
.then(function (res) {
|
|
6186
6186
|
/* a project that ANSWERED but refused (its own pre-launch gate, a proxy
|
|
6187
6187
|
error page) is not an older core — carry the status, don't guess */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"surface": "public-landing",
|
|
5
5
|
"modes": ["dark"],
|
|
6
6
|
"modeQuery": false,
|
|
7
|
-
"ignoreRequests": ["/api/(gds|bongos)/me$", "/my-projects", "/provisioning/instances/999", "/provisioning/instances/101$", "/api/
|
|
7
|
+
"ignoreRequests": ["/api/(gds|bongos)/me$", "/my-projects", "/provisioning/instances/999", "/provisioning/instances/101$", "/api/bongos/instance$", "/github/repos$", "/provisioning/onboard-plan"],
|
|
8
8
|
"ignoreConsole": ["/api/(gds|bongos)/me", "\\b401\\b", "\\b404\\b", "Unauthorized"],
|
|
9
9
|
"ignoreControls": [".skip", ".vh"],
|
|
10
10
|
"states": {
|
package/modules/sessions/db.js
CHANGED
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
|
|
25
25
|
const api = require('../../src/module-api');
|
|
26
26
|
const { pool } = api;
|
|
27
|
+
// The PURE verdict + every clamp and threshold (task 1003865). The module's own
|
|
28
|
+
// file, not the doorway: it touches no kernel surface, and keeping the numbers
|
|
29
|
+
// in one place is what stops the route and the poller disagreeing.
|
|
30
|
+
const uploadHealth = require('./upload-health');
|
|
27
31
|
// `seams` is the doorway's kernel-mediated seam surface (resolveOptional/resolve).
|
|
28
32
|
// upsertSessionRecordWithReward resolves the economy `reward` port through it —
|
|
29
33
|
// the module↔module seam, never a sibling-module require (BV1.R77 / ADR 0093 §2).
|
|
@@ -656,6 +660,118 @@ async function filterTaskIdsClaimedBy(builderId, taskIds) {
|
|
|
656
660
|
return rows.map((r) => Number(r.task_id));
|
|
657
661
|
}
|
|
658
662
|
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
// -------------------------------------------------------------------------
|
|
666
|
+
// Session-upload health (task 1003865) — is the corpus still being written?
|
|
667
|
+
// -------------------------------------------------------------------------
|
|
668
|
+
//
|
|
669
|
+
// THE SIGNAL. The server already knows both halves independently: a task reached
|
|
670
|
+
// status='shipped', and whether that task's builder uploaded any session around
|
|
671
|
+
// then. A ship with no session record for its builder inside a window is the unit
|
|
672
|
+
// of evidence. Before this, the ONLY trace of a skipped upload was a jsonl file on
|
|
673
|
+
// the builder's own laptop, so a weeks-long outage that stopped every cost-plus
|
|
674
|
+
// reward from booking was invisible from the server.
|
|
675
|
+
//
|
|
676
|
+
// GROUPED BY BUILDER, which is the entire design and is measured, not assumed —
|
|
677
|
+
// see ../upload-health for the numbers. The corpus-wide share cannot see the
|
|
678
|
+
// outage (3.4% in its worst month, against 1.7-2.0% in healthy ones); per builder
|
|
679
|
+
// the same data fires on 13 days, all inside the outage window, all one builder.
|
|
680
|
+
//
|
|
681
|
+
// KEYED ON builder_id + TIME, NEVER ON task_ids. session_records.task_ids is
|
|
682
|
+
// EMPTY on 54% of rows (1,771 of 3,873 when task 1002448 measured it), so the
|
|
683
|
+
// obvious predicate — "no session record NAMES this task" — reports the linkage
|
|
684
|
+
// gap as an outage. Neither query below mentions task_ids, and a test asserts
|
|
685
|
+
// that about the SQL these functions actually emit.
|
|
686
|
+
//
|
|
687
|
+
// Every threshold and clamp lives in ../upload-health (PURE, unit-tested), so the
|
|
688
|
+
// route and the poller cannot answer this question two different ways.
|
|
689
|
+
|
|
690
|
+
// sessionUploadCoverage — per-BUILDER ship counts over the lookback, and how many
|
|
691
|
+
// of those ships had NO session record for that builder inside the window. One
|
|
692
|
+
// query, server-side, deliberately: /sessions/search is rate-limited per builder
|
|
693
|
+
// and clamps limit to 100, so paging the corpus from a client to compute this is
|
|
694
|
+
// neither cheap nor reliable (measured while scoping this task — 45 pages, with
|
|
695
|
+
// 429s).
|
|
696
|
+
async function sessionUploadCoverage({ days, windowHours } = {}) {
|
|
697
|
+
const d = uploadHealth.clampLookbackDays(days);
|
|
698
|
+
const w = uploadHealth.clampWindowHours(windowHours);
|
|
699
|
+
const { rows } = await pool.query(
|
|
700
|
+
`SELECT t.shipped_by AS builder_id,
|
|
701
|
+
b.github_login,
|
|
702
|
+
COUNT(*)::int AS ships,
|
|
703
|
+
COUNT(*) FILTER (
|
|
704
|
+
WHERE NOT EXISTS (
|
|
705
|
+
SELECT 1
|
|
706
|
+
FROM session_records sr
|
|
707
|
+
WHERE sr.builder_id = t.shipped_by
|
|
708
|
+
AND sr.uploaded_at >= t.shipped_at - ($2 * interval '1 hour')
|
|
709
|
+
AND sr.uploaded_at <= t.shipped_at + ($2 * interval '1 hour')
|
|
710
|
+
)
|
|
711
|
+
)::int AS uncovered
|
|
712
|
+
FROM tasks t
|
|
713
|
+
JOIN builders b ON b.id = t.shipped_by
|
|
714
|
+
WHERE t.status = 'shipped'
|
|
715
|
+
AND t.shipped_by IS NOT NULL
|
|
716
|
+
AND t.shipped_at IS NOT NULL
|
|
717
|
+
AND t.shipped_at >= now() - ($1 * interval '1 day')
|
|
718
|
+
GROUP BY t.shipped_by, b.github_login
|
|
719
|
+
ORDER BY 4 DESC`,
|
|
720
|
+
[d, w]
|
|
721
|
+
);
|
|
722
|
+
return { days: d, windowHours: w, rows };
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// shipsMissingSessionRecord — the offending ships themselves, newest first. The
|
|
726
|
+
// verdict says how bad and whose; this says WHICH, because recovering the unpaid
|
|
727
|
+
// work needs the task ids and a percentage does not carry them. Bounded by
|
|
728
|
+
// clampSampleLimit: evidence, not a report.
|
|
729
|
+
async function shipsMissingSessionRecord({ days, windowHours, limit, builderId } = {}) {
|
|
730
|
+
const d = uploadHealth.clampLookbackDays(days);
|
|
731
|
+
const w = uploadHealth.clampWindowHours(windowHours);
|
|
732
|
+
const n = uploadHealth.clampSampleLimit(limit);
|
|
733
|
+
const b = Number.isFinite(Number(builderId)) ? Number(builderId) : null;
|
|
734
|
+
const { rows } = await pool.query(
|
|
735
|
+
`SELECT t.id, t.title, t.shipped_by, b.github_login, t.shipped_at
|
|
736
|
+
FROM tasks t
|
|
737
|
+
JOIN builders b ON b.id = t.shipped_by
|
|
738
|
+
WHERE t.status = 'shipped'
|
|
739
|
+
AND t.shipped_by IS NOT NULL
|
|
740
|
+
AND t.shipped_at IS NOT NULL
|
|
741
|
+
AND t.shipped_at >= now() - ($1 * interval '1 day')
|
|
742
|
+
AND ($3::bigint IS NULL OR t.shipped_by = $3)
|
|
743
|
+
AND NOT EXISTS (
|
|
744
|
+
SELECT 1
|
|
745
|
+
FROM session_records sr
|
|
746
|
+
WHERE sr.builder_id = t.shipped_by
|
|
747
|
+
AND sr.uploaded_at >= t.shipped_at - ($2 * interval '1 hour')
|
|
748
|
+
AND sr.uploaded_at <= t.shipped_at + ($2 * interval '1 hour')
|
|
749
|
+
)
|
|
750
|
+
ORDER BY t.shipped_at DESC
|
|
751
|
+
LIMIT ${n}`,
|
|
752
|
+
[d, w, b]
|
|
753
|
+
);
|
|
754
|
+
return rows;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// sessionUploadHealth — the whole answer in one call: the verdict, the per-builder
|
|
758
|
+
// counts behind it, and a sample of the ships it is counting. The route serves
|
|
759
|
+
// this and the poller logs from it, so neither owns the arithmetic. The sample is
|
|
760
|
+
// skipped entirely when nothing is uncovered — the healthy path costs one query.
|
|
761
|
+
async function sessionUploadHealth({ days, windowHours, sampleLimit } = {}) {
|
|
762
|
+
const coverage = await sessionUploadCoverage({ days, windowHours });
|
|
763
|
+
const verdict = uploadHealth.uploadHealthVerdict(coverage.rows);
|
|
764
|
+
const sample = verdict.uncovered > 0
|
|
765
|
+
? await shipsMissingSessionRecord({ days, windowHours, limit: sampleLimit })
|
|
766
|
+
: [];
|
|
767
|
+
return {
|
|
768
|
+
days: coverage.days,
|
|
769
|
+
window_hours: coverage.windowHours,
|
|
770
|
+
verdict,
|
|
771
|
+
sample,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
|
|
659
775
|
module.exports = {
|
|
660
776
|
// write side (6D.1)
|
|
661
777
|
upsertSessionRecord,
|
|
@@ -667,6 +783,10 @@ module.exports = {
|
|
|
667
783
|
// search + fetch (6D.2)
|
|
668
784
|
searchSessions,
|
|
669
785
|
summarizeSessions,
|
|
786
|
+
// upload health (task 1003865) — is the corpus still being written at all?
|
|
787
|
+
sessionUploadCoverage,
|
|
788
|
+
shipsMissingSessionRecord,
|
|
789
|
+
sessionUploadHealth,
|
|
670
790
|
getSessionById,
|
|
671
791
|
listSessionsByBuilder,
|
|
672
792
|
filterTaskIdsClaimedBy,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"key": "sessions",
|
|
3
3
|
"title": "Sessions & BFG (session corpus · efficiency eval)",
|
|
4
|
-
"description": "The session-records corpus + its data plane (POST /sessions upload, the Archon-gated cross-builder /sessions/search + /sessions/:id deep-dive), the BFG 'read-the-room' cross-builder scorer (ADR 0026 §6B), and the session-pulse / stale-claim heartbeat helpers. A core-domain module carved out of the GDS core in BV1.R82 (ADR 0093 §1); default-on because every instance records its builders' sessions for the BFG. Like the memory module, sessions registers no port — core never calls back into it: the ship-time digest write is an HTTP POST to the module's own /sessions route, and the only outward dependency is the economy `reward` kernel PORT it resolves (session token reward + sumCreditsForTasks) at upload time.",
|
|
4
|
+
"description": "The session-records corpus + its data plane (POST /sessions upload, the Archon-gated cross-builder /sessions/search + /sessions/:id deep-dive + /sessions/upload-health, the server-side signal that a builder's session uploads have silently stopped), the BFG 'read-the-room' cross-builder scorer (ADR 0026 §6B), and the session-pulse / stale-claim heartbeat helpers. A core-domain module carved out of the GDS core in BV1.R82 (ADR 0093 §1); default-on because every instance records its builders' sessions for the BFG. Like the memory module, sessions registers no port — core never calls back into it: the ship-time digest write is an HTTP POST to the module's own /sessions route, and the only outward dependency is the economy `reward` kernel PORT it resolves (session token reward + sumCreditsForTasks) at upload time.",
|
|
5
5
|
"coreVersion": "^1.10.0",
|
|
6
6
|
"default": true,
|
|
7
7
|
"maintenance": { "status": "core-maintained" },
|
|
8
|
-
"contributes": { "routes": ["sessions"], "pollers": ["session-reward-reconcile"] },
|
|
8
|
+
"contributes": { "routes": ["sessions"], "pollers": ["session-reward-reconcile", "session-upload-health"] },
|
|
9
9
|
"provides": [],
|
|
10
10
|
"consumes": []
|
|
11
11
|
}
|