@bongos/core 1.18.0 → 1.18.3

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.
Files changed (113) hide show
  1. package/.bongos-core.json +132 -322
  2. package/README.md +1 -1
  3. package/config/branding.neutral.json +5 -1
  4. package/docs/adr/0142-project-context-is-prose-only.md +41 -0
  5. package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
  6. package/docs/adr/README.md +5 -2
  7. package/docs/api/openapi.json +1789 -450
  8. package/docs/api-reference.md +52 -5
  9. package/docs/file-map.md +7 -7
  10. package/docs/recipes/packaging-the-core.md +13 -0
  11. package/docs/recipes/upgrading-the-core.md +5 -2
  12. package/migrations/039_newcomer_friendly_column.sql +5 -0
  13. package/migrations/102_remove_box_first_provision_approval.sql +4 -0
  14. package/migrations/core_192_github_oauth_tokens.sql +33 -0
  15. package/modules/hall-ui/public/my-projects.html +78 -0
  16. package/modules/hall-ui/public/my-projects.js +142 -0
  17. package/modules/hall-ui/public/scouting.html +45 -0
  18. package/modules/hall-ui/public/scouting.js +73 -0
  19. package/modules/status-ui/public/explore.html +54 -0
  20. package/modules/status-ui/public/explore.js +67 -0
  21. package/package-lock.json +2 -2
  22. package/package.json +1 -1
  23. package/public-landing/create.html +211 -14
  24. package/scripts/gds/cli-lib.js +11 -5
  25. package/scripts/gds/lint-migrations.js +102 -0
  26. package/scripts/gds/login.js +42 -10
  27. package/scripts/gds/mirror-redact.js +5 -0
  28. package/scripts/gds/package-core.js +263 -4
  29. package/scripts/gds/provision.js +145 -7
  30. package/scripts/gds/publish-manifest.js +15 -0
  31. package/scripts/gds/run-unit-tests.js +38 -14
  32. package/scripts/gds/setup.js +41 -0
  33. package/scripts/gds/ship.js +115 -31
  34. package/scripts/gds/upgrade.js +147 -5
  35. package/scripts/migrate.sh +10 -0
  36. package/src/bongos/auth.js +362 -5
  37. package/src/bongos/db.js +66 -0
  38. package/src/bongos/github-repos.js +93 -0
  39. package/src/bongos/routes/auth.js +93 -11
  40. package/src/bongos/routes/github.js +90 -0
  41. package/src/bongos/routes/instance.js +15 -3
  42. package/src/bongos/routes.js +2 -0
  43. package/src/branding.js +17 -2
  44. package/src/instance-config.js +16 -0
  45. package/src/module-api.js +29 -1
  46. package/tests/branding.mjs +29 -23
  47. package/tests/github_repos_helpers.mjs +91 -0
  48. package/tests/github_token_store.mjs +121 -0
  49. package/tests/idp_device_exchange.mjs +105 -0
  50. package/tests/idp_federation.mjs +100 -0
  51. package/tests/migrations_forward_safe.mjs +86 -0
  52. package/tests/module_api.mjs +1 -1
  53. package/tests/package_core.mjs +246 -1
  54. package/tests/provision.mjs +157 -0
  55. package/tests/pruned_lockfile_integrity.mjs +79 -0
  56. package/tests/ship_ci_deploy.mjs +60 -0
  57. package/tests/upgrade.mjs +254 -5
  58. package/.gitignore +0 -91
  59. package/docs/adr/0139-platform-history-migration-to-cloudbongos.md +0 -94
  60. package/docs/adr/0140-cloudbongos-standalone-reprovision.md +0 -43
  61. package/scripts/hall-preview/fixtures/access-requests.json +0 -20
  62. package/scripts/hall-preview/fixtures/achievements.json +0 -76
  63. package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
  64. package/scripts/hall-preview/fixtures/audit-log.json +0 -68
  65. package/scripts/hall-preview/fixtures/blockers__detail.json +0 -12
  66. package/scripts/hall-preview/fixtures/box__me.json +0 -5
  67. package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -69
  68. package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
  69. package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
  70. package/scripts/hall-preview/fixtures/builders__roster.json +0 -48
  71. package/scripts/hall-preview/fixtures/goals.json +0 -502
  72. package/scripts/hall-preview/fixtures/goals__25.json +0 -96
  73. package/scripts/hall-preview/fixtures/goals__26.json +0 -67
  74. package/scripts/hall-preview/fixtures/goals__3.json +0 -103
  75. package/scripts/hall-preview/fixtures/goals__35.json +0 -49
  76. package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
  77. package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
  78. package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
  79. package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
  80. package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -32
  81. package/scripts/hall-preview/fixtures/inbox.json +0 -330
  82. package/scripts/hall-preview/fixtures/inbox__detail.json +0 -15
  83. package/scripts/hall-preview/fixtures/instance.json +0 -124
  84. package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
  85. package/scripts/hall-preview/fixtures/me.json +0 -476
  86. package/scripts/hall-preview/fixtures/me__art-key__own.json +0 -6
  87. package/scripts/hall-preview/fixtures/me__event-sound-prefs.json +0 -209
  88. package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
  89. package/scripts/hall-preview/fixtures/me__render.json +0 -5
  90. package/scripts/hall-preview/fixtures/me__skill-prefs.json +0 -143
  91. package/scripts/hall-preview/fixtures/me__sound-prefs.json +0 -67
  92. package/scripts/hall-preview/fixtures/me__wandering.json +0 -43
  93. package/scripts/hall-preview/fixtures/override-requests.json +0 -15
  94. package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
  95. package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
  96. package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
  97. package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
  98. package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
  99. package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
  100. package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
  101. package/scripts/hall-preview/fixtures/public__grades.json +0 -50
  102. package/scripts/hall-preview/fixtures/public__progress.json +0 -124
  103. package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
  104. package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
  105. package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
  106. package/scripts/hall-preview/fixtures/security__docs.json +0 -10
  107. package/scripts/hall-preview/fixtures/security__reports.json +0 -31
  108. package/scripts/hall-preview/fixtures/sessions__search.json +0 -9
  109. package/scripts/hall-preview/fixtures/tasks.json +0 -2420
  110. package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
  111. package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
  112. package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
  113. package/scripts/hall-preview/fixtures/versions.json +0 -89
@@ -1,330 +0,0 @@
1
- {
2
- "ideas": [
3
- {
4
- "id": "535",
5
- "title": "cloudbongos.com gate JS is Cloudflare-cached ~4h with no purge-on-deploy — gate fixes lag for users",
6
- "body_md": "Surfaced while shipping task 2146 (gate minimap fix). The origin (cloudbongos.com droplet) pulled the fix within its 2-min timer, but real users kept getting the OLD gate JS because Cloudflare edge-cached it.\n\n**Root gap:** `brand/cloud-bongos/gate/*.js` is served with `cache-control: max-age=14400` (4h) and Cloudflare caches it at the edge. `scripts/deploy/deploy-cloudbongos.sh` has NO cache-purge step, and the box's only CF token (`/etc/cloudbongos/box.env`, DNS:Edit + Zone:Read scope) is rejected by `purge_cache` (code 10000). So every gate code change is invisible to users for up to ~4h after deploy.\n\n**Fix options:**\n- (a) Add `Zone:Cache Purge` to the box CF token, then append a targeted `purge_cache` call (for changed static files) to the end of `deploy-cloudbongos.sh`.\n- (b) Lower the asset `cache-control` and/or add a content-hash/version query to the `space.js` include in `gate/index.html` so a new deploy busts the cache automatically.\n\nOption (b) is the more robust, secret-free fix (no token widening).\n",
7
- "kind": "infra",
8
- "suggested_version": "BONGOS-V1",
9
- "suggested_priority": null,
10
- "captured_at": "2026-07-09T21:12:55.282Z",
11
- "captured_by": "1",
12
- "status": "open",
13
- "promoted_to_task_id": null,
14
- "reviewed_at": null
15
- },
16
- {
17
- "id": "534",
18
- "title": "package-core: consumer core still ships amazonprimea/OTB refs in SKILL.md + cli-lib API_BASE fallback (CLAUDE.md already stubbed)",
19
- "body_md": "While verifying task 2131 (fresh demo re-provision on @bongos/core 1.17.1), the CLAUDE.md\nstub (task 2121) is confirmed clean — 18/18 core CLAUDE.md are stubs, 0 CLAUDE.md leak. BUT a\nwhole-tree sweep of the fresh demo checkout found ~213 files still referencing\n\"amazonprimea\"/\"off the boats\"/\"hermeslines\" — in .claude/skills/*/SKILL.md and the vendored\ncore copy (node_modules/@bongos/core/.claude/skills/). Characterized as NON-functional for a\nhosted instance (identity resolves from branding.neutral.json → demo.cloudbongos.com; web+CLI\nsign-in verified correct), because it's two things: (a) cli-lib.js's fallback default\n`const API_BASE = ic.resolveEnv('API_BASE') || 'https://amazonprimea.com'` — a consumer running\nthe raw CLI UNCONFIGURED would hit the OTB prod URL; (b) stale prose examples in SKILL.md docs.\nThis may be the deliberate \"verbatim functional files\" design (see memory\nproject-consumer-core-extraction-verbatim; CLAUDE.md stubbing was the exception). Proposal for\ntriage: decide whether package-core should also (1) neutralize the API_BASE fallback (resolve\nfrom branding publicOrigin, or no hardcoded default) and (2) scrub/neutralize brand refs in\nshipped SKILL.md, the way task 2121 did for CLAUDE.md. Relates to tasks 2121/1824, goal 26\n(CB↔OTB switchover / consumer cleanliness).\n",
20
- "kind": "cleanup",
21
- "suggested_version": "BONGOS-V1",
22
- "suggested_priority": null,
23
- "captured_at": "2026-07-09T17:21:24.975Z",
24
- "captured_by": "1",
25
- "status": "open",
26
- "promoted_to_task_id": null,
27
- "reviewed_at": null
28
- },
29
- {
30
- "id": "533",
31
- "title": "2103 rebrand/prune gaps + config-dir collision found live-refreshing demo (2102–2105 follow-ups)",
32
- "body_md": "Found while live-refreshing ~/dev/demo (2026-07-08) to carry the 2102–2105 onboarding fixes. Three concrete follow-ups on the fixes just shipped:\n\n1. **Rebrand misses `User-Agent` product literals (2103 gap).** `buildRebrandRules`/`rebrandText` map origins, config-dirs and env-prefixes, but NOT the founder product name baked into HTTP `User-Agent` strings. After a full re-materialize of demo, 5 hooks still carry `amazonprimea-*` UA labels: `recall-hints.js`, `stop-refcheck.js`, `rank-change-greeting.js`, `conductor.js`, `pull-memory.js`. Cosmetic (the hooks target the right instance — only their self-identification leaks the founder brand), but it undercuts \"clean instance.\" Fix: add the `<founder-name>-` UA literal to the rebrand map (source brand identity.* → target).\n\n2. **Re-materialize never prunes now-excluded skills (2103 gap, upgrade path only).** `materializeClaude({overwrite:true})` copies-over but never DELETES. On a re-materialize/`bongos upgrade` over a prior materialize, every skill owned by a module that is disabled in the target lingers from the old copy — all 5 `otb-*` disabled-module skills stayed until pruned by hand. Fresh `bongos init` (empty .claude) is unaffected. Fix: after copying, remove instance skill dirs that are in `disabledModuleSkills()` (or, more general, reconcile — delete instance-side skill dirs not present in the new copy set).\n\n3. **Sibling instances collide on one session slot (config-dir gap).** `demo.cloudbongos.com` and `cloudbongos.com` both resolve configDir to the `cloudbongos` fallback → they share `~/.config/cloudbongos/gds-session.json`, so logging into one clobbers the other on the same machine. Consider pinning a per-instance `configDir` at provision (e.g. slug-derived) so several instances can be signed in side-by-side.\n\nAlso surfaced (separate, bigger): the packaged core deliberately excludes `.claude/hooks/` (publish-manifest), so hook fixes like 2105 can only reach an instance via a full-checkout materialize (control-plane provision), NOT via the vendored tarball / `bongos upgrade`. Fine today (all instances are control-plane-provisioned), but the future pure-npm-consumer path (task 2090) would ship an instance with skills and no hooks. And CORE_VERSION was NOT bumped for 2102–2105, so the version string no longer uniquely identifies a core tree.\n",
33
- "kind": "bug",
34
- "suggested_version": "BONGOS-V1",
35
- "suggested_priority": null,
36
- "captured_at": "2026-07-08T23:22:27.719Z",
37
- "captured_by": "1",
38
- "status": "open",
39
- "promoted_to_task_id": null,
40
- "reviewed_at": null
41
- },
42
- {
43
- "id": "531",
44
- "title": "Provisioned instances ignore config/branding.json (GDS_BRANDING_FILE points at nonexistent branding.neutral.json)",
45
- "body_md": "Provisioned standalone instances may ignore their own config/branding.json overrides.\n\nprovision.js `webEnvBody` writes `GDS_BRANDING_FILE=config/branding.neutral.json`, but the scaffold (init.js `writeConfigs`) writes the instance's identity/overrides to `config/branding.json`, NOT `branding.neutral.json`. On demo.cloudbongos.com the instance therefore loads the NEUTRAL base pack (no firstAdmin, default productName) and identity rides only web.env env-overrides (origins + the new `<prefix>_FIRST_ADMIN` from task 2079). So productName / worldName / currency set at `init` don't load until the owner re-brands.\n\nLikely fix: point `GDS_BRANDING_FILE` at `config/branding.json` (init.js's real output) OR have provision.js also emit those identity fields as env-overrides. Verify src/branding.js still merges the neutral base underneath (GDS_BRANDING_FILE = the OVERRIDES file, neutral = base).\n\nFound while fixing the FIRST_ADMIN gap (task 2079, goal 35 / criterion 165).\n",
46
- "kind": "bug",
47
- "suggested_version": "BONGOS-V1",
48
- "suggested_priority": null,
49
- "captured_at": "2026-07-07T23:17:01.521Z",
50
- "captured_by": "1",
51
- "status": "open",
52
- "promoted_to_task_id": null,
53
- "reviewed_at": null
54
- },
55
- {
56
- "id": "529",
57
- "title": "Single-host standalone: /docs + /docs/openapi.json 404 at the edge (isModuleSurfaceHost skips apex-only routes when public/builders/status are one host)",
58
- "body_md": "On a SINGLE-HOST standalone (demo.cloudbongos.com — publicOrigin = buildersOrigin = statusOrigin = one host), /docs and /docs/openapi.json return 404 at the public edge even though the files ship and loopback /docs -> 200.\n\nCAUSE: serve-internal.js gates /docs on `if (isModuleSurfaceHost(req)) return next();` (docs live on the apex, skipped for builders./status. surfaces). In single-host mode the apex host ALSO equals buildersOrigin/statusOrigin, so isModuleSurfaceHost(req) is TRUE for the apex host and /docs is wrongly skipped -> 404. Loopback (Host 127.0.0.1) doesn't match, so it serves.\n\nFIX DIRECTION: isModuleSurfaceHost must not treat the apex host as a module surface when public/builders/status collapse to one host — apex-only routes (/docs, /docs/openapi.json, /downloads/*) should still serve. Check other apex-only surfaces for the same single-host skip. Found during the task-2078 demo audit (2026-07-07).\n",
59
- "kind": "bug",
60
- "suggested_version": "BONGOS-V1",
61
- "suggested_priority": null,
62
- "captured_at": "2026-07-07T18:06:08.665Z",
63
- "captured_by": "1",
64
- "status": "open",
65
- "promoted_to_task_id": null,
66
- "reviewed_at": null
67
- },
68
- {
69
- "id": "528",
70
- "title": "Standalone-on-control-plane TLS: bake proxied=true for wildcard-origin-cert subdomains (+ fix tls-check 404 on control plane)",
71
- "body_md": "Discovered during task 2074 live activation (standing up demo.cloudbongos.com on the control-plane droplet 161.35.132.201).\n\nPROBLEM: provision.js/box-dns-cloudflare.sh create the instance A record with proxied=false (the co-tenant \"on-demand ACME / Let's Encrypt\" posture, ADR 0111 §4). But a *.cloudbongos.com subdomain on the CONTROL-PLANE box is shadowed by the wildcard Cloudflare Origin cert already loaded for the apexes (SAN *.cloudbongos.com, ADR 0126). Caddy serves that origin cert and never triggers on-demand ACME, so a DIRECT client (proxied=false) gets a publicly-UNTRUSTED cert (issuer: CloudFlare Origin CA) -> browser cert warning. It also exposes the control-plane's real IP in public DNS (worse here than for a game box, since this box holds the account tokens).\n\nSTOPGAP APPLIED: manually flipped demo.cloudbongos.com to proxied=true via the CF API (CF edge now fronts it with a public cert, origin cert valid behind Full-strict, IP hidden). Verified: public HTTPS returns a Google Trust Services cert, healthz ok.\n\nFIX (code): make the DNS proxied flag shape/placement-aware. For a STANDALONE instance whose domain falls under a zone where the control plane holds a wildcard origin cert (i.e. *.cloudbongos.com on this box), set proxied=true; otherwise keep proxied=false (co-tenant + custom-domain standalones still want on-demand ACME). Likely a boxExec-sibling decision in provision.js (dnsUpsertEnv) + a proxied param on box-dns-cloudflare.sh (currently hardcoded proxied:false). Consider an ADR — this is the TLS analogue of the task-2074 executor/IP shape-split.\n\nALSO: GET /api/bongos/provisioning/tls-check?domain=demo.cloudbongos.com returns 404 on the control-plane cloudbongos instance (the on-demand-TLS allow-list gate). Verify the provisioning module is enabled + current there; a 404 means on-demand ACME couldn't gate even if it did fire. Lower priority once proxied=true is the posture for *.cloudbongos.com.\n\nDepends on: task 2074 (shipped).\n",
72
- "kind": "bug",
73
- "suggested_version": "BONGOS-V1",
74
- "suggested_priority": null,
75
- "captured_at": "2026-07-07T11:21:23.244Z",
76
- "captured_by": "1",
77
- "status": "open",
78
- "promoted_to_task_id": null,
79
- "reviewed_at": null
80
- },
81
- {
82
- "id": "527",
83
- "title": "Agents module goal cluster (#38/#39/#40): finalize criteria + seed tasks (Archon)",
84
- "body_md": "# Agents module — goal cluster finalization bundle (2026-07-05/06)\n\n**Goals created (BONGOS-V1):** [#38] framework+registry · [#39] owner+builder authoring + event/on-demand roster · [#40] scheduled agents + spend guardrails. Created unscoped (scope wall rejects `agents` until the module is registered — retighten `scope_modules=['agents']` after Phase-1 task lands modules/agents/module.json).\n\n**Owner decisions (2026-07-05):** full framework + full roster; audiences owners+builders now, **end-users deferred** to a documented future goal (Phase 3); trigger types all three (event/cron/on-demand); **per-agent spend cap ~$5/mo** on top of the global ~$30/mo autonomy brake.\n\n**Load-bearing constraint (from adversarial critique):** the spawn primitive `grader.js runSubagent` is **fixed Read-only + bypassPermissions** (`--tools Read` hardcoded; only `model/cwd/timeout` are parametrizable). So **v1 agents are READ-ONLY observe-and-report** — no write principals, no Bash/Write/network, no tool-allowlist tiers in Phases 1–2. Trust model is **capability-equivalence, not rank-equivalence**: an agent's runtime authority = its tool set ∩ its (absent, in v1) service principal; author-rank only clamps what may be *declared*. Any write-capable/act-capable agent is DEFERRED to a future goal that first lands a parametrized-capability spawn path in grading (a PROTECTED_GLOBS edit, Archon-gated). Also drop the proposed new `grade.runSubagent` port — the existing `grade` provider already exposes `runSubagentCached`.\n\n**Finalization is Archon-gated** (jaxri is Metic): creating done-when criteria is `POST /api/bongos/versions/BONGOS-V1/done-when` (Archon-only), and core-touching tasks (grading/lifecycle/permission-paths) need Archon. Run `/planning-session` as Archon, or create criteria + tasks below, then link each criterion's gating tasks (`task_criteria`) and set `goal_id`.\n\n---\n\n## Goal #38 — Framework + registry (Phase 1)\n\n**Done-when criteria (outcome-shaped):**\n1. An agent declared in `.claude/agents/<name>.md` loads into the `agent_definitions` registry at boot, and `GET /api/bongos/agents` returns it with its resolved model tier + trigger type.\n2. A malformed definition (unknown trigger; missing persona; `trigger_spec.event` not in `EVENT_CATALOG`; scope exceeding an allowed module) is rejected by a pure `validateAgentDefinition()` with a clear error and does NOT mount (loader logs + skips, never crashes). `EVENT_CATALOG = ['task.shipped']` and fail-closed refuses any unwired event name.\n3. Every agent spawn goes through the existing `grade` port (`runSubagentCached`, read-only) and is billed to the LLM cost cache — no bespoke `child_process.spawn`; the modules-boundary fitness check stays green (no module→module require).\n4. An agent with no explicit `model_tier` defaults to `subagentDefault`; each spawn passes the branding-resolved concrete model id as `opts.model`.\n5. The built-in `historian` on-demand exemplar ships enabled and returns a cited result end-to-end via `scripts/gds/agent-invoke.js`.\n6. `agents-sync.js` reconciles `.claude/agents/*.md` → rows (`source=file`, never clobbering `source=db` rows), stamps `author_rank` from the committing builder's LIVE DB rank, re-runs the scope wall server-side (a definition scoped onto protected paths imports disabled+flagged, never armed), and every fire writes one `agent_runs` row (trigger_ref, gate decision, cost_usd, output_ref).\n\n**Seed tasks (deps in parens):**\n- T1 `modules/agents/module.json` (default:false; contributes routes/pollers/skills/migrations) validated by manifest-schema.js\n- T2 `modules/agents/migrations/agents_001_definitions.sql` — `agent_definitions` + `agent_runs`, namespaced\n- T3 `modules/agents/lib/validate.js` — pure `validateAgentDefinition(obj,{authorRank})` (EVENT_CATALOG=['task.shipped'], enum + scope-wall checks) (T1)\n- T4 `modules/agents/routes/agents.js` — `GET /agents`, `GET /agents/:name` (self-gated reads) (T1,T2)\n- T5 spawn adapter: resolve `model_tier`→concrete id via `api.branding()`, consume existing `grade.runSubagentCached`, write an `agent_runs` ledger row per fire (T2)\n- T6 `scripts/gds/agents-sync.js` — file↔DB reconcile at deploy; source=file upsert never clobbers source=db; stamps live author_rank + re-runs scope wall (T2,T3)\n- T7 `scripts/gds/agent-invoke.js` + `.claude/agents/historian.md` (reads ADR/session-log/learnings corpus, returns cited answers) (T4,T5)\n- T8 add `.claude/agents/` to permission-path awareness so a definition scoped onto permission paths is caught (T3)\n\n## Goal #39 — Owner + builder authoring + event/on-demand roster (Phase 2a) — depends on #38\n\n**Done-when criteria:**\n1. A Metic+ builder creates an agent via `POST /api/bongos/agents` and it appears in the registry with no Archon file edit; a sub-Metic author, or any author whose scope touches a protected/permission path, is refused server-side (DB-enforced; no file grants authority).\n2. Runtime authority is capability-equivalence: v1 agents are READ-ONLY (no write/service principal); author-rank clamps only what may be DECLARED (scope/trigger/model tier), enforced by the upward-only clamp + goalScopeCheck/permissionPathCheck scope wall.\n3. The on-ship event fabric fires on `task.shipped` only when the declarative `touches[]`-glob matches (cheap pre-filter BEFORE any model spawn), lands its finding in its declared sink (ideas.capture / Discord), and NEVER blocks the ship (observe-only; only the DB-gated Grader gates landing).\n4. Ships ≥1 working exemplar for event (`review-lens`) and on-demand (`historian`, `planner`), each defined in `.claude/agents/` not JS; `GET /agents` distinguishes built-in vs instance-authored provenance.\n5. Editing a definition + reload updates the row in place (no duplicate); disabling an agent stops it from being dispatched.\n\n**Seed tasks:**\n- rank-gated `POST/PATCH/DELETE/enable/disable/invoke` routes with the author-rank declaration clamp + scope wall\n- `modules/agents/pollers/event-router.js` — `api.on('task.shipped')` fan-out with the declarative touches[]-glob pre-filter + a depth/loop guard (never fire on an agent's own agent_runs-attributed ship) + spawn + route-output\n- roster `.claude/agents/*.md` (event): `review-lens`, `doc-link-keeper`, `dep-security-watch` (each on task.shipped + touches filter)\n- roster `.claude/agents/*.md` (on-demand): `historian`, `planner`, `onboarding-buddy`\n- clone-templates `art-tile-reviewer` + `world-consistency` marked `template:true` (load only where art-pipeline/game enabled)\n\n## Goal #40 — Scheduled agents + spend guardrails (Phase 2b) — depends on #39\n\n**Done-when criteria:**\n1. A scheduled agent runs on its `config/scheduled-routines.json` cadence via an in-process unref timer, opens with `autonomy-gate.decide()`, is inert until `OTB_AUTONOMY_ENABLED=1` if it writes state; an agent over the MTD ceiling is skipped with the skip recorded to `autonomy_runs`.\n2. Per-agent `spend_cap_usd` (default ~$5/mo) is enforced before spawn; agent spend is tagged `agent:<key>` and folded into the MTD rollup the deterministic gate reads, so cron + on-demand agent spend is visible to the brake.\n3. No roster agent re-executes an existing routine's state change — each wrapper declares `backing_routine` and either observes its output or replaces the routine (retiring the `scheduled-routines.json` entry in the same task). No double-run.\n4. The agents module's own tables/routes + `config/scheduled-routines.json` are covered by PROTECTED_GLOBS with a fitness assertion.\n5. The cron roster ships as `.claude/agents/*.md`: `ship-digest` (weekly), `link-sweep` (nightly), `criteria-watch` (nightly), `stale-claim-nudge` (daily).\n\n**Seed tasks:**\n- `modules/agents/pollers/cron-router.js` — one unref routine-timer per cadence bucket; each tick selects due cron agents + runs Step-0 autonomy precheck\n- extend MTD rollup + autonomy-gate so `source LIKE 'agent:%'` folds into the `cron:%` brake; add per-agent `spend_cap_usd` enforced before spawn (agents_002 migration)\n- add agents module tables/routes + `config/scheduled-routines.json` to PROTECTED_GLOBS (permission-path-check.js) + a fitness assertion\n- cron roster `.claude/agents/*.md`: ship-digest, link-sweep, criteria-watch, stale-claim-nudge (each declaring backing_routine; wrap, don't double-run)\n\n---\n\n## Deferred — Phase 3 (documented future goal, NOT created)\n**End-user-facing agent authorship** — the biggest trust jump (untrusted input meets a principal). Gated behind Phases 1–2. End-users get NO free-text authorship: they only instantiate an owner-published (Archon-only) template with typed/validated params; untrusted text enters strictly as delimited DATA. Capability-first defense: a dedicated low-priv `system_role=agent:enduser:<key>` principal, on-demand-only, `--tools Read`, output=return, `model=subagentRoutine`, SQL reads scoped to the end-user's own rows, per-user spend/rate quota, propose-never-dispose for any state change; operator global-disable flag; its own ADR. Create as a Phase-3 goal in a later planning pass once 1–2 are proven in production.\n\n## New ADRs to write during the build\n- Agents module architecture (definition format, registry, spawn-via-grade-port, trust = capability-equivalence, v1 read-only).\n- (Later) End-user agent trust model (Phase 3).\n",
85
- "kind": "bug",
86
- "suggested_version": "BONGOS-V1",
87
- "suggested_priority": null,
88
- "captured_at": "2026-07-06T00:02:09.772Z",
89
- "captured_by": "95",
90
- "status": "open",
91
- "promoted_to_task_id": null,
92
- "reviewed_at": null
93
- },
94
- {
95
- "id": "526",
96
- "title": "cloudbongos own-provision runner unit missing on control plane (verify vs in-flight 2056)",
97
- "body_md": "During the task 2071/2072 co-hosting-fleet migration (2026-07-05), I noticed the control-plane box (161.35.132.201) had `cloudbongos-provision-intent-runner.{service,timer}` installed + enabled + actively firing at ~22:36 UTC (task 2056's runner that drains cloudbongos.com's OWN provisioning_intents queue in the LOCAL cloudbongos DB). By ~23:2x UTC both unit files were GONE from /etc/systemd/system and `is-enabled` = not-found.\n\nMy 2071/2072 work never touched that name (I added cohost-* units + removed the differently-named provision-intent-runner-cloudbongos.* from task 2065; scp only added files). The control-plane pull-deploy only installs, never removes units. So this was removed by something else — most likely a parallel session's in-flight task 2056 (e2e standup) box work (that task is explicitly about updating the on-box provision-intent-runner; PR #772 from a parallel branch merged around the same window). It is a BOX-ONLY unit (not in repo infra/), so its removal leaves no git trace.\n\nImpact right now: LOW — the cloudbongos DB provisioning_intents queue is empty (0 pending, 0 provisioning_instances), so nothing is stuck. But if this was unintentional, cloudbongos.com's own instance-provisioning has NO drainer, and the next builders.cloudbongos.com instance request would sit forever (the \"queue never drains\" class 2056 was meant to fix).\n\nACTION: whoever owns task 2056 — confirm this removal is intended by the in-flight standup restructuring. If NOT intended, restore/re-enable a local-cloudbongos-DB provisioning runner on the control plane. Do NOT confuse it with cohost-provision-intent-runner (task 2071), which drains the AMAZONPRIMEA queue via the SSH tunnel, not the local cloudbongos DB.\n",
98
- "kind": "bug",
99
- "suggested_version": "BONGOS-V1",
100
- "suggested_priority": null,
101
- "captured_at": "2026-07-05T23:27:47.112Z",
102
- "captured_by": "1",
103
- "status": "open",
104
- "promoted_to_task_id": null,
105
- "reviewed_at": null
106
- },
107
- {
108
- "id": "524",
109
- "title": "Deploy-time reconcile of the live Caddyfile vs repo infra/Caddyfile (on_demand_tls global + sites import)",
110
- "body_md": "Surfaced during the goal-35 standup (task 2066 gap 2): the droplet's live /etc/caddy/Caddyfile drifts from repo infra/Caddyfile with no auto-sync. The `on_demand_tls { ask http://127.0.0.1:3002/api/bongos/provisioning/tls-check }` global + `import /etc/caddy/sites/*.caddy` had to be hand-applied on 161.35.132.201 (and 104.236.254.243). provision.js writes per-instance snippets into /etc/caddy/sites but ASSUMES the global import + on_demand_tls ask already exist.\n\nProposal: a deploy-time (or provision-preflight) reconcile step that idempotently ensures the base Caddyfile carries the on_demand_tls global + the sites/*.caddy import, runs `caddy validate`, then gracefully reloads — so a fresh control-plane box is provisioning-ready without manual Caddyfile surgery. Complements ADR 0128 (the privilege model) — that fixed the runner's ability to WRITE the snippets; this ensures the base config actually IMPORTS them.\n",
111
- "kind": "infra",
112
- "suggested_version": "BONGOS-V1",
113
- "suggested_priority": null,
114
- "captured_at": "2026-07-05T21:34:40.548Z",
115
- "captured_by": "1",
116
- "status": "open",
117
- "promoted_to_task_id": null,
118
- "reviewed_at": null
119
- },
120
- {
121
- "id": "523",
122
- "title": "search-ingest-md: a NUL byte rolls back the whole /recall ingest",
123
- "body_md": "`scripts/gds/search-ingest-md.js` rolls back the ENTIRE ingest when any one chunk body contains a NUL byte (U+0000): Postgres rejects it with `invalid byte sequence for encoding \"UTF8\": 0x00`, so `/recall` never re-indexes.\n\n- **Surfaced by** the new cloudbongos deploy timer (task 2064) — the deploy's search-index step logged it (non-fatal, so the deploy is unaffected).\n- **Pre-existing + affects the co-hosting box identically** — same tree-walk + same code; there it's swallowed the same way, so amazonprimea.com's `/recall` may also be silently stale.\n- No *tracked* `.md` contains a raw NUL, so the byte is introduced in the chunk pipeline (`modules/memory/search-chunker.js`) or a generated/untracked `.md` on the box — worth a quick root-cause check.\n- **Fix:** strip the NUL (U+0000) from chunk bodies in `chunkFile()` (or right after `fs.readFileSync(abs,'utf8')`) before the upsert — NUL is invalid in a PG text column and meaningless in prose. Low-risk; fixes both boxes at once.\n",
124
- "kind": "bug",
125
- "suggested_version": "BONGOS-V1",
126
- "suggested_priority": null,
127
- "captured_at": "2026-07-05T21:27:59.832Z",
128
- "captured_by": "1",
129
- "status": "open",
130
- "promoted_to_task_id": null,
131
- "reviewed_at": null
132
- },
133
- {
134
- "id": "522",
135
- "title": "Builder profile: shareable-by-login deep links (?builder=<login>)",
136
- "body_md": "The v1 builder profile page (task 1467) resolves by numeric ?id=N, matching /builders/:id/onboarding. Friendlier, more shareable portfolio links would accept a github_login (/builders/profile?builder=<login>) and resolve login->id server-side — either a login lookup in the GET /builders/:id/profile route or a sibling by-login route in src/bongos/routes/builders.js. Small fast-follow to goal 25 bx-identity.\n",
137
- "kind": "feature",
138
- "suggested_version": "BONGOS-V1",
139
- "suggested_priority": null,
140
- "captured_at": "2026-07-05T20:01:18.464Z",
141
- "captured_by": "95",
142
- "status": "open",
143
- "promoted_to_task_id": null,
144
- "reviewed_at": null
145
- },
146
- {
147
- "id": "521",
148
- "title": "Repo deploy-prod.sh mirror is stale vs droplet ~/deploy.sh (missing ADR 0122 block)",
149
- "body_md": "Repo deploy-script mirror is stale vs the droplet.\n\n`scripts/deploy/deploy-prod.sh` (the version-controlled mirror) is missing the ADR 0122 onboarding-diagram-render block (~17 lines, task 2027) that IS live in `/home/lars/deploy.sh` on prod. The file header explicitly warns that this exact drift is what hid the task-1026 healthcheck race for so long.\n\nFix: pull the droplet's current `~/deploy.sh` back into `scripts/deploy/deploy-prod.sh` so the two are byte-faithful again. Verify with `diff` after.\n\nFound while inspecting the deploy path for task 2020 (observability stand-up).\n",
150
- "kind": "bug",
151
- "suggested_version": "BONGOS-V1",
152
- "suggested_priority": null,
153
- "captured_at": "2026-07-05T16:31:34.762Z",
154
- "captured_by": "1",
155
- "status": "open",
156
- "promoted_to_task_id": null,
157
- "reviewed_at": null
158
- },
159
- {
160
- "id": "520",
161
- "title": "Wire Grafana dashboard-sync into the prod deploy hook (task 2020 follow-up)",
162
- "body_md": "Wire Grafana dashboard-sync into the prod deploy hook.\n\nAfter `git reset --hard origin/main`, the deploy should `cp infra/grafana/dashboards/*.json` + `provisioning/*` into `/etc/grafana` so a repo dashboard edit actually reaches live Grafana (its file provider auto-reloads every 30s). Today (post task 2020) the stack is live and dashboards render, but a repo dashboard edit needs a manual on-box `cp` to propagate.\n\nDo-with / blocked-on: reconcile the `scripts/deploy/deploy-prod.sh` repo mirror against the droplet's `~/deploy.sh` first (see sibling capture) so adding the sync step doesn't regress the drifted diagram-render block.\n\nNB: a symlink into the repo checkout will NOT work — the packaged `grafana-server` unit sets `ProtectHome=true`, so the grafana process cannot read a repo under `/home`. The copy must land in `/etc/grafana` (or be done by a root-run sync).\n\nDiscovered standing up the observability stack (task 2020).\n",
163
- "kind": "infra",
164
- "suggested_version": "BONGOS-V1",
165
- "suggested_priority": null,
166
- "captured_at": "2026-07-05T16:31:34.363Z",
167
- "captured_by": "1",
168
- "status": "open",
169
- "promoted_to_task_id": null,
170
- "reviewed_at": null
171
- },
172
- {
173
- "id": "518",
174
- "title": "Make goal # more direct in UI for users to reference, offer an easy copy paste on the goal so they can just make progress on what is priority in that goal",
175
- "body_md": "Make goal # more direct in UI for users to reference, offer an easy copy paste on the goal so they can just make progress on what is priority in that goal\n\n— filed from Discord #ideas by lars589",
176
- "kind": "feature",
177
- "suggested_version": null,
178
- "suggested_priority": null,
179
- "captured_at": "2026-07-05T15:59:24.532Z",
180
- "captured_by": "1",
181
- "status": "open",
182
- "promoted_to_task_id": null,
183
- "reviewed_at": null
184
- },
185
- {
186
- "id": "517",
187
- "title": "Default-goal (goal 3 'BONGOS-V1 general') is blocked by goal 26 → every default POST /tasks task is born un-claimable",
188
- "body_md": "Goal 3 (\"BONGOS-V1 — general\") — the auto-created catch-all that every `POST /tasks` task defaults into when no `goal_id` is given — carries an unsatisfied goal→goal dependency on goal 26 (\"Cloud Bongos productization and self-host\", status open).\n\nBecause `claimTask`'s `unsatisfiedDeps` inherits the task's goal dependencies (ADR 0086 §5, modules/lifecycle/db.js), EVERY task created via the default path is born `ready` but un-claimable — it fails `DEPS_NOT_SHIPPED` on goal 26 until goal 26 is achieved.\n\nHit while filing the box.js teardown bug (task 2034): the task defaulted into goal 3 and couldn't be claimed; I had to recreate it under goal 25 (\"Builder experience — hall, dev box, and skills\") to proceed.\n\nThis looks like a misconfigured/backwards edge — a catch-all \"general\" goal shouldn't gate on a specific feature goal, and it silently makes the most common create path produce dead tasks.\n\nFix candidates (verify intent first):\n- (a) remove the goal 3 → goal 26 dependency edge; or\n- (b) make the default-goal picker (generalGoalIdForVersion) skip a blocked goal, or never inherit deps from the catch-all general goal.\n",
189
- "kind": "bug",
190
- "suggested_version": "BONGOS-V1",
191
- "suggested_priority": null,
192
- "captured_at": "2026-07-04T16:30:59.466Z",
193
- "captured_by": "1",
194
- "status": "open",
195
- "promoted_to_task_id": null,
196
- "reviewed_at": null
197
- },
198
- {
199
- "id": "516",
200
- "title": "Land task 1952: convert its ~20 pre-ADR-0116 flat errors (or run R04 sweep 1991) so the ratchet passes",
201
- "body_md": "Task 1952 (Private goals API, branch claude/reverent-ellis-4774d9) is confirmed, merged-with-main, and green EXCEPT the ADR-0116 flat-error ratchet: its ~20 new routes in modules/lifecycle/routes/goals.js use the old flat `res.status(n).json({error:'x'})` style (branch predates the convention), pushing FLAT_ERROR_BASELINE over 562 → api_error_envelope_buildcheck + fitness fail.\n\nTo land: either (a) convert those ~20 sites to `res.fail('code',{status,message})` — safe, consumers key on HTTP status not the .error string (verified for 1658's expand endpoint) — then re-push + nudge publish-status; or (b) let the R04 sweep (task 1991) convert them wholesale.\n\nSystemic: the same ratchet will block ANY in-flight PR (of the ~20 open) that adds routes with flat errors. Consider sequencing the R04 sweep before/alongside landing the in-flight route-adding PRs.\n",
202
- "kind": "bug",
203
- "suggested_version": "BONGOS-V1",
204
- "suggested_priority": null,
205
- "captured_at": "2026-07-04T15:13:00.205Z",
206
- "captured_by": "1",
207
- "status": "open",
208
- "promoted_to_task_id": null,
209
- "reviewed_at": null
210
- },
211
- {
212
- "id": "515",
213
- "title": "[task 2028 follow-up] Fitness guard: no hardcoded host identity in scheduled-routine prose",
214
- "body_md": "Add a fitness check extending the \"portable code carries no hardcoded host identity\" spirit to .claude/scheduled-tasks/*/SKILL.md prose (grep the instance domain + ~/.config/<slug> patterns; hardFail on match). Task 2028 swept all 7 offending routine files clean and verified by re-grep, but the existing fitness host-identity check only scans src/gds + modules + kernel CLIs, so a future edit could reintroduce a hardcoded amazonprimea.com / ~/.config/otb into a routine with nothing to catch it. Deliberately NOT bolted onto 2028 to avoid adding an instance-wide CI gate under a docs-sweep task. Low-risk: after 2028 there are zero matches, so the guard passes immediately.",
215
- "kind": "cleanup",
216
- "suggested_version": null,
217
- "suggested_priority": null,
218
- "captured_at": "2026-07-04T14:46:22.115Z",
219
- "captured_by": "1",
220
- "status": "open",
221
- "promoted_to_task_id": null,
222
- "reviewed_at": null
223
- },
224
- {
225
- "id": "511",
226
- "title": "Goal managers can properly edit tasks (abandon, prioritize, and add dependencies on tasks from the UI)",
227
- "body_md": "Goal managers can properly edit tasks (abandon, prioritize, and add dependencies on tasks from the UI)\n\n— filed from Discord #ideas by lars589",
228
- "kind": "feature",
229
- "suggested_version": null,
230
- "suggested_priority": null,
231
- "captured_at": "2026-07-04T11:57:12.146Z",
232
- "captured_by": "1",
233
- "status": "open",
234
- "promoted_to_task_id": null,
235
- "reviewed_at": null
236
- },
237
- {
238
- "id": "510",
239
- "title": "Goal 3 (general) has an unintended dep edge on goal 26 — blocks all general tasks",
240
- "body_md": "Goal 3 (\"BONGOS-V1 — general\") carries a dependency edge on goal 26 (Cloud Bongos productization, status open). Via `db.js` `unsatisfiedDeps()` goal-dependency inheritance, ANY task under the general goal is unclaimable (409 DEPS_NOT_SHIPPED) until goal 26 is achieved.\n\nAlmost certainly unintended — \"general\" work should not be gated on productization shipping. Found 2026-07-04 while landing goal 36 (the meta planning task 1987 hit this 409 before being re-parented onto goal 36).\n\nFix: verify the `dependencies` row (from_kind=goal, from_id=3, to_kind=goal, to_id=26) and delete it if unintended. Also worth an audit for other surprising goal→goal edges.\n",
241
- "kind": "bug",
242
- "suggested_version": "BONGOS-V1",
243
- "suggested_priority": null,
244
- "captured_at": "2026-07-04T11:16:51.960Z",
245
- "captured_by": "1",
246
- "status": "open",
247
- "promoted_to_task_id": null,
248
- "reviewed_at": null
249
- },
250
- {
251
- "id": "509",
252
- "title": "Emersonian droplet needs a GitHub deploy key for one-command core-pin upgrades",
253
- "body_md": "The emersonian-circles droplet checkout (/home/lars/emersonian-circles) can't `git pull` from the private repo github.com/lars589/emersonian-circles — no deploy key (`Permission denied (publickey)`). During the task-1973 de-fork, the intended \"pin-bump upgrade flow\" (git pull + npm ci + restart) couldn't run, so the upgrade shipped via a scp'd git bundle instead.\n\nFix: add a read-only GitHub **deploy key** (or switch the remote to an https-token URL) on the droplet so future core-pin bumps are a one-command `git pull && npm ci && npm run migrate && systemctl restart`.\n\nRelevant to goal 26 R86 (task 1690 — make `bongos upgrade` a real update channel) and the standalone-instance provisioning direction (a provisioned standalone instance needs a deploy path from its private repo).\n",
254
- "kind": "feature",
255
- "suggested_version": "BONGOS-V1",
256
- "suggested_priority": null,
257
- "captured_at": "2026-07-04T00:58:44.176Z",
258
- "captured_by": "1",
259
- "status": "open",
260
- "promoted_to_task_id": null,
261
- "reviewed_at": null
262
- },
263
- {
264
- "id": "508",
265
- "title": "more achievements to promote full platform usage",
266
- "body_md": "more achievements to promote full platform usage\n\n— filed from Discord #ideas by scootermack",
267
- "kind": "feature",
268
- "suggested_version": null,
269
- "suggested_priority": null,
270
- "captured_at": "2026-07-03T22:34:10.998Z",
271
- "captured_by": "94",
272
- "status": "open",
273
- "promoted_to_task_id": null,
274
- "reviewed_at": null
275
- },
276
- {
277
- "id": "507",
278
- "title": "Durable module enable/disable persistence past a deploy",
279
- "body_md": "The hall Modules-tab toggle (task 1776, ADR 0107 §9) writes config/modules.json\nand reloads the live in-process module cache, so the effect is immediate on the\nbox. But deploy-prod.sh runs `git reset --hard origin/main` on every deploy,\nwhich would silently wipe an uncommitted toggle. Today the route deliberately\ndoes NOT auto-commit/push (an HTTP handler pushing to main bypasses the ship/\ngrade/deploy pipeline entirely — a bigger risk than the toggle not persisting).\n\nOptions to revisit: (a) a DB-backed override layer in src/modules.js's\nresolution precedence (checked above the instance config file, below env) so\nenablement survives a `git reset --hard` with no extra step, matching \"the GDS\nDB is the source of truth for live state\"; or (b) a reviewed, narrowly-scoped\nauto-commit-and-push path for this one config file if that's judged safe\nenough. See src/gds/routes/modules.js's top-of-file comment for the full\ntradeoff as reasoned through in task 1776.\n",
280
- "kind": "feature",
281
- "suggested_version": "BONGOS-V1",
282
- "suggested_priority": null,
283
- "captured_at": "2026-07-03T20:38:28.576Z",
284
- "captured_by": "94",
285
- "status": "open",
286
- "promoted_to_task_id": null,
287
- "reviewed_at": null
288
- },
289
- {
290
- "id": "506",
291
- "title": "tests/sandbox_stage.mjs no-op check fails on macOS (/var symlink); realpath both sides in syncWorktreeToServed",
292
- "body_md": "tests/sandbox_stage.mjs — the sub-test \"syncWorktreeToServed: no-op when the session checkout IS the served root\" (~line 414) FAILS on macOS but passes on Linux CI.\n\nRoot cause: syncWorktreeToServed (scripts/gds/sandbox-stage.js:246) decides \"no-op\" via `path.resolve(sessionRoot) === path.resolve(servedRoot)`. sessionRoot comes from `git rev-parse --show-toplevel`, which git realpaths to `/private/var/folders/...` on macOS, while servedRoot is the raw `os.tmpdir()` path `/var/folders/...`. path.resolve does NOT resolve the macOS `/var → /private/var` symlink, so the two mismatch, the no-op branch is skipped, and `synced` returns true instead of false. On Linux CI `/tmp` has no such symlink, so it passes.\n\nFix: `fs.realpathSync` both paths before comparing (in the function, which also hardens the real box behavior, or at minimum in the test setup). Low priority — macOS-local test-run only; does not affect prod or CI. Surfaced while shipping task 1439 (the failure looked scary in the local unit gate but is environmental).\n",
293
- "kind": "bug",
294
- "suggested_version": "BONGOS-V1",
295
- "suggested_priority": null,
296
- "captured_at": "2026-07-03T20:16:28.581Z",
297
- "captured_by": "1",
298
- "status": "open",
299
- "promoted_to_task_id": null,
300
- "reviewed_at": null
301
- },
302
- {
303
- "id": "505",
304
- "title": "Neutralize per-branch auth error prose (heading/detail still hardcode Archon/gate) — idea 351 follow-up to task 1439",
305
- "body_md": "Task 1439 made renderAuthErrorPage's TEMPLATE strings brand-aware (title suffix / epigraph / h1 / default subtitle / default CTA now come from the branding pack `copy.authError`). But the `heading` + `detail` arguments passed by each call site in src/gds/routes/auth.js (the /auth/web/callback error branches, roughly lines 270–463) still hardcode OTB lore that renders on cloudbongos.com and every other instance:\n\n- \"...Start over and the gate will open.\" (state-mismatch branch)\n- \"...an Archon has already approved...\" / \"...an Archon will approve you...\" (NOT_APPROVED branch, incl. its opts.subtitle/note)\n- \"...the Archon must investigate the server logs.\" (500 branch)\n\nFix: source these per-branch strings from the branding pack too (add more `copy.authError.*` keys, or rephrase neutrally using rankLabels for \"Archon\"→\"Owner\"), mirroring the 1439 approach. This is the broader \"neutralize ALL auth-page copy\" pass that 1439 deliberately scoped out (1439 = the template defaults only). From idea 351 follow-up.\n",
306
- "kind": "bug",
307
- "suggested_version": "BONGOS-V1",
308
- "suggested_priority": null,
309
- "captured_at": "2026-07-03T20:16:28.166Z",
310
- "captured_by": "1",
311
- "status": "open",
312
- "promoted_to_task_id": null,
313
- "reviewed_at": null
314
- },
315
- {
316
- "id": "504",
317
- "title": "goal due dates",
318
- "body_md": "goal due dates\n\n— filed from Discord #ideas by jaxri",
319
- "kind": "feature",
320
- "suggested_version": null,
321
- "suggested_priority": null,
322
- "captured_at": "2026-07-03T18:46:38.300Z",
323
- "captured_by": "95",
324
- "status": "open",
325
- "promoted_to_task_id": null,
326
- "reviewed_at": null
327
- }
328
- ],
329
- "open_count": 151
330
- }
@@ -1,15 +0,0 @@
1
- {
2
- "idea": {
3
- "id": "1",
4
- "title": "Preview-harness idea record — serves any #/idea/N deep-link",
5
- "body_md": "Synthetic record for the shared deep-link overlay (task-detail.js). One fixture serves every id via the inbox/\\d+ fallback.",
6
- "kind": "feature",
7
- "suggested_version": "BONGOS-V1",
8
- "suggested_priority": null,
9
- "captured_at": "2026-07-01T12:00:00.000Z",
10
- "captured_by": "1",
11
- "status": "open",
12
- "promoted_to_task_id": null,
13
- "reviewed_at": null
14
- }
15
- }
@@ -1,124 +0,0 @@
1
- {
2
- "schema": "instance-manifest/v1",
3
- "name": "Off the Boats",
4
- "brand": {
5
- "identity": {
6
- "productName": "Off the Boats",
7
- "worldName": "Amazonprimea",
8
- "company": {
9
- "name": "Hermeslines"
10
- }
11
- },
12
- "currency": {
13
- "label": "drachmae",
14
- "symbol": ""
15
- },
16
- "theme": {
17
- "colors": {
18
- "bg": "#ece0c2",
19
- "bgCard": "#f6ecd2",
20
- "bgDeep": "#ddc99c",
21
- "bgFrame": "#e3d0a4",
22
- "ink": "#2a2110",
23
- "inkSoft": "#6e5b3a",
24
- "inkFaint": "#735f3d",
25
- "rule": "#8b6f2c",
26
- "ruleSoft": "#b89a55",
27
- "accent": "#4a7d5c",
28
- "accentDeep": "#2f5a3f",
29
- "sea": "#2d6e7e",
30
- "terracotta": "#a85530"
31
- },
32
- "fonts": {
33
- "display": "\"Cinzel\", \"Cormorant Garamond\", \"Trajan Pro\", \"Iowan Old Style\", Georgia, serif",
34
- "body": "\"EB Garamond\", \"Iowan Old Style\", \"Hoefler Text\", Georgia, serif",
35
- "links": [
36
- "https://fonts.googleapis.com/css2?family=Cinzel:wght@500;700&family=EB+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&display=swap"
37
- ]
38
- },
39
- "favicon": "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text x='16' y='24' font-size='24' text-anchor='middle' font-family='serif'>Α</text></svg>",
40
- "backdrop": "linear-gradient(180deg, #fde8c8 0%, #fff4e6 45%, #fffdfa 100%)"
41
- },
42
- "copy": {
43
- "tagline": "Goods straight off the boats.",
44
- "hallName": "Builders' Hall",
45
- "notFound": "You've washed ashore on the wrong island."
46
- },
47
- "rankLabels": {
48
- "xenos": "Xenos",
49
- "thetes": "Thetes",
50
- "metic": "Metic",
51
- "archon": "Archon"
52
- }
53
- },
54
- "modules": {
55
- "enabled": {
56
- "art-pipeline": true,
57
- "autonomy": true,
58
- "builder-settings": true,
59
- "character-anim": true,
60
- "demo": true,
61
- "dev-box": true,
62
- "discord": true,
63
- "economy": true,
64
- "game": true,
65
- "grading": true,
66
- "hall-ui": true,
67
- "ideas": true,
68
- "lifecycle": true,
69
- "memory": true,
70
- "onboarding": true,
71
- "provisioning": true,
72
- "security": true,
73
- "sessions": true,
74
- "status-ui": true
75
- },
76
- "disciplines": [
77
- "engineer",
78
- "ideator",
79
- "artist"
80
- ]
81
- },
82
- "ranks": [
83
- {
84
- "key": "xenos",
85
- "tier": 1,
86
- "label": "Xenos"
87
- },
88
- {
89
- "key": "thetes",
90
- "tier": 2,
91
- "label": "Thetes"
92
- },
93
- {
94
- "key": "metic",
95
- "tier": 3,
96
- "label": "Metic"
97
- },
98
- {
99
- "key": "archon",
100
- "tier": 4,
101
- "label": "Archon"
102
- }
103
- ],
104
- "repo": {
105
- "owner": "lars589",
106
- "repo": "amazonprimea",
107
- "branch": "main",
108
- "url": "https://github.com/lars589/amazonprimea"
109
- },
110
- "auth": {
111
- "methods": [
112
- "device-flow",
113
- "web",
114
- "app-pair"
115
- ],
116
- "configured": true
117
- },
118
- "admission": {
119
- "policy": "invite-only"
120
- },
121
- "devBox": {
122
- "available": true
123
- }
124
- }