@bongos/core 1.19.335 → 1.19.336

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.
@@ -1,1981 +0,0 @@
1
- #!/usr/bin/env node
2
- // Seed the 80 net-new GDS-V3 tasks defined in V3 Planning Session #1
3
- // (CLAUDE.md session log 2026-05-12 GDS-V3 planning).
4
- //
5
- // Idempotent: skips tasks whose source_ref already exists.
6
- //
7
- // Companion migration 018_pms_v3_planning_seed.sql handles:
8
- // - 9 done_when_criteria seed rows
9
- // - versions.GDS-V3.done_when text update
10
- // - 9 existing-task priority + V3.R## title-prefix updates
11
- //
12
- // This script handles the 80 net-new task creates + the 10 idea-promotion
13
- // PATCH calls that mark the source ideas as 'promoted' with their new
14
- // promoted_to_task_id.
15
- //
16
- // Ranking convention: priority is 1-5 (CHECK constraint). Fine-grained
17
- // 89-deep ordering lives in the V3.R## title prefix (zero-padded for sort).
18
- // Tier mapping: T1=P5, T2=P5, T3=P4, T4=P4, T5=P3, T6=P2, T7=P1.
19
- //
20
- // Usage: node scripts/gds/seed-v3-tasks.js [--dry-run]
21
-
22
- const { cliClient, requireSession } = require('./cli-lib');
23
-
24
- const DRY = process.argv.includes('--dry-run');
25
-
26
- // ---------------------------------------------------------------------------
27
- // The 80 net-new tasks
28
- // ---------------------------------------------------------------------------
29
- //
30
- // Each entry: { ref, title, description, kind, discipline, priority,
31
- // est_minutes, manual_degree, credits_reward, touches,
32
- // promoted_idea_id? }
33
- //
34
- // `ref` doubles as source_ref ("gds-v3-r##") and as the V3.R## title prefix.
35
-
36
- const TASKS = [
37
- // =========================================================================
38
- // TIER 1 — Bedrock (P5). Must ship before Builder #2 arrives.
39
- // =========================================================================
40
-
41
- {
42
- ref: 'R01',
43
- title: 'Rename GDS → GDS (backend folders, routes, env vars; "credits→drachmae" frontend-only)',
44
- description: `**Criterion:** cross-cutting (identity).
45
-
46
- **Why:** GDS-V3 opens the system to multiple builders; the "Project Management System" name is internal and feels off when the thing is actually the Game Development System for an entire civilization. Rename now while there's only one builder; deferring multiplies the cost across N builders.
47
-
48
- **Scope (V3):**
49
- - Backend folder: \`src/pms/\` → \`src/bongos/\` (incl. routes/, db.js, auth.js, etc.)
50
- - Scripts: \`scripts/pms/\` → \`scripts/gds/\`
51
- - API path: \`/api/pms/*\` → \`/api/gds/*\` (keep \`/api/pms/*\` as 301 redirect for one version)
52
- - Env vars: \`PMS_*\` → \`GDS_*\`
53
- - Frontend label: "credits" displayed as "drachmae" everywhere on \`/builders\` + \`/status\` (no schema rename of \`credits_reward\` / \`credit_log\` — that's a separate task)
54
- - All skill files updated to call new paths
55
- - CLAUDE.md / README / docs updated
56
-
57
- **Done when:**
58
- - \`/api/gds/me\` returns 200 with current builder
59
- - \`/api/pms/me\` returns 301 to the new path
60
- - All 14 GDS slash commands work after the rename
61
- - "drachmae" label visible on \`/builders\` and \`/status\` profile/leaderboard rows
62
-
63
- **Cross-refs:** Promotes idea_inbox #11. All subsequent V3 tasks reference the new \`src/bongos/\` paths.`,
64
- kind: 'refactor',
65
- discipline: 'engineering',
66
- priority: 5,
67
- est_minutes: 480,
68
- manual_degree: 2,
69
- credits_reward: 80,
70
- touches: ['src/pms/', 'scripts/pms/', 'server.js', 'public-status/', 'public-builders/', '.claude/skills/', 'CLAUDE.md', 'README.md'],
71
- promoted_idea_id: 11,
72
- },
73
-
74
- {
75
- ref: 'R02',
76
- title: 'Architecture spike — server-enforced trust boundary (output ADR + sub-tasks)',
77
- description: `**Criterion:** C7 — server-enforced permissions.
78
-
79
- **Why:** Before we build rank-check middleware, route auditors, and a periodic auditor cron, we need an explicit design for the trust boundary: where does authority live, how is it checked, what is the exact failure mode when a builder edits their local files. This spike outputs an ADR and generates the actual implementation tasks for C7.
80
-
81
- **Done when:**
82
- - ADR \`docs/adr/0015-trust-boundary-server-enforced-permissions.md\` describes: where rank lives (DB), how it's checked (every privileged request hits the DB, no token caching), how skills/hooks/settings.json are bounded, what files describe vs what files enforce
83
- - Implementation sub-tasks created for C7 with parent_task_id pointing at this spike: covers route middleware, audit pass, periodic auditor, CLAUDE.md disclaimer, token issuance design
84
- - Trust-model diagram included in the ADR
85
-
86
- **Cross-refs:** Gates V3.R05, V3.R06, V3.R44, V3.R45 (the C7 implementation tasks). Output reshapes them if needed.`,
87
- kind: 'spike',
88
- discipline: 'engineering',
89
- priority: 5,
90
- est_minutes: 180,
91
- manual_degree: 3,
92
- credits_reward: 40,
93
- touches: ['docs/adr/'],
94
- },
95
-
96
- {
97
- ref: 'R03',
98
- title: 'Architecture spike — cloneability + local-first memory with server sync',
99
- description: `**Criterion:** C8 — cloneable repo, local-first memory, server-canonical on ship.
100
-
101
- **Why:** Same pattern as R02. Before we build memory sync infrastructure, we need a design: what's the schema for server-side memory, how do we resolve conflicts between local and server, how does pull-on-session-start interact with worktree creation, what happens when a builder's machine dies.
102
-
103
- **Done when:**
104
- - ADR \`docs/adr/0016-cloneable-repo-local-first-memory.md\` describes: server schema (Postgres BYTEA vs object storage), sync trigger (ship-time push, session-start pull), conflict policy (last-write-wins per file, or merge), isolation (per-builder, no cross-reads), backup cadence
105
- - Implementation sub-tasks created for C8 with parent_task_id pointing here
106
- - Portability test plan included: fresh clone → setup → ready to ship
107
-
108
- **Cross-refs:** Gates V3.R55–V3.R63 (the C8 implementation tasks). Output reshapes the memory schema + sync mechanics.`,
109
- kind: 'spike',
110
- discipline: 'engineering',
111
- priority: 5,
112
- est_minutes: 180,
113
- manual_degree: 3,
114
- credits_reward: 40,
115
- touches: ['docs/adr/'],
116
- },
117
-
118
- {
119
- ref: 'R05',
120
- title: 'Server-side requireRank() middleware on every privileged GDS API route',
121
- description: `**Criterion:** C2, C7 — three ranks gate everything; server-side enforcement.
122
-
123
- **Why:** With \`builders.rank\` enum added by R04 (#106), every privileged endpoint needs to check rank against the DB. No token-side caching — checked on every request so rank changes propagate immediately.
124
-
125
- **Done when:**
126
- - \`src/bongos/auth.js\` exposes \`requireRank(minRank)\` middleware that returns 403 \`{error: 'rank_too_low', required, actual}\` on failure
127
- - Applied to every route flagged Metic+ or Archon+ in R02's ADR (routes file by file)
128
- - Unit-test smoke: Xenos session calling a Metic+ route → 403; Archon session calling everything → 200
129
- - Output of R02 (the spike) drives the exact route list
130
-
131
- **Cross-refs:** Depends on R02 (spike) + R04 (rank enum). Blocks R06.`,
132
- kind: 'feature',
133
- discipline: 'engineering',
134
- priority: 5,
135
- est_minutes: 240,
136
- manual_degree: 2,
137
- credits_reward: 40,
138
- touches: ['src/bongos/auth.js', 'src/bongos/routes/'],
139
- },
140
-
141
- {
142
- ref: 'R06',
143
- title: 'PATCH /api/gds/builders/:id/rank — Archon-only promotion AND demotion endpoint',
144
- description: `**Criterion:** C2 — three ranks gate everything.
145
-
146
- **Why:** Archon needs a way to promote Xenos → Metic and demote in reverse. Endpoint is the single chokepoint for rank changes; everything logs to audit_log (R36 dependency).
147
-
148
- **Done when:**
149
- - \`PATCH /api/gds/builders/:id/rank { rank: 'Metic' | 'Xenos' | 'Archon' }\` works
150
- - requireRank('Archon') guards it
151
- - Cannot demote yourself (no last-Archon footgun)
152
- - Writes to audit_log (when R36 is shipped; until then, writes to credit_log with reason='rank_change' + the actor)
153
- - Returns updated builder row
154
- - Smoke test: Archon promotes a Xenos → 200, rank flips; same Xenos tries to demote Archon → 403
155
-
156
- **Cross-refs:** Depends on R04 (rank column) + R05 (middleware). Cross-link to R29 (promotion ceremony).`,
157
- kind: 'feature',
158
- discipline: 'engineering',
159
- priority: 5,
160
- est_minutes: 120,
161
- manual_degree: 2,
162
- credits_reward: 20,
163
- touches: ['src/bongos/routes/builders.js', 'src/bongos/db.js'],
164
- },
165
-
166
- {
167
- ref: 'R07',
168
- title: '/builder-setup audit — strip every Archon-only assumption (paths, hostnames, ssh, deploy keys)',
169
- description: `**Criterion:** C1 — onboarding ≤ 2h.
170
-
171
- **Why:** \`scripts/pms/setup.js\` and the surrounding \`/builder-setup\` skill currently assume Lars's machine (paths like \`~/.config/otb/\`, expects \`~/.claude/credentials.json\` shape from one Anthropic account, hardcoded \`lars589\` references in test code, deploy-key paths). A second builder runs it and hits cryptic failures. Audit + fix every assumption.
172
-
173
- **Done when:**
174
- - A clean-checkout builder on a different machine completes \`/builder-setup\` end-to-end without manual edits
175
- - No string \`lars\`, \`lars589\`, \`lars@\`, or \`Lars\` in any setup-path code
176
- - Setup writes to \`~/.config/otb/pms-session.json\` regardless of OS/user
177
- - \`/builder-setup --dry-run\` mode prints what it would do, for newcomer reassurance
178
- - Smoke test runs in a fresh worktree as a fresh "user" (env var override of homedir)
179
-
180
- **Cross-refs:** Cross-link to R08 (bootstrap script) + R11 (authorship audit).`,
181
- kind: 'cleanup',
182
- discipline: 'engineering',
183
- priority: 5,
184
- est_minutes: 180,
185
- manual_degree: 2,
186
- credits_reward: 30,
187
- touches: ['scripts/gds/setup.js', '.claude/skills/otb-builder-setup/', 'scripts/gds/cli-lib.js'],
188
- },
189
-
190
- {
191
- ref: 'R08',
192
- title: 'scripts/setup-builder.sh — one-command bootstrap (Node/Python checks, npm ci, .env.local, /builder-setup)',
193
- description: `**Criterion:** C1 — onboarding ≤ 2h.
194
-
195
- **Why:** Today onboarding requires the builder to know what to install in what order. We want \`./scripts/setup-builder.sh\` to be the one thing they run.
196
-
197
- **Done when:**
198
- - Script verifies Node ≥22 and Python ≥3.10, prints actionable error if missing
199
- - Runs \`npm ci\`
200
- - Copies \`.env.local.example\` to \`.env.local\` (prompts for Gemini key, or accepts \`--skip-keys\`)
201
- - Runs \`node scripts/gds/setup.js\` (the Device Flow auth)
202
- - Prints "you're ready — run \`/builder-start\` next"
203
- - Idempotent: re-run on an already-set-up checkout doesn't blow anything up
204
- - README updated to point new builders at this script
205
-
206
- **Cross-refs:** Depends on R07 (audited \`/builder-setup\`). Verified by R17 (V3 hello-world smoke).`,
207
- kind: 'feature',
208
- discipline: 'engineering',
209
- priority: 5,
210
- est_minutes: 90,
211
- manual_degree: 2,
212
- credits_reward: 15,
213
- touches: ['scripts/setup-builder.sh', 'README.md', '.env.local.example'],
214
- },
215
-
216
- {
217
- ref: 'R09',
218
- title: 'Anthropic account linking via Claude Code self-verification during /builder-setup',
219
- description: `**Criterion:** C3 — per-builder credentials with authorship.
220
-
221
- **Why:** We need to know which Anthropic account is making GDS API calls so cost + authorship attribution works across N builders. Per-OAuth from Anthropic doesn't exist yet, but Claude Code itself is the trusted agent on the builder's machine — it can read its own credentials and refuse to proceed if the typed email doesn't match.
222
-
223
- **Approach:**
224
- - During \`/builder-setup\`, prompt builder for their Anthropic email
225
- - Read local Claude Code credentials (\`~/.claude/credentials.json\` or equivalent in current Claude Code version)
226
- - Compare; abort with clear error if mismatch
227
- - On success, store \`anthropic_email\` + \`anthropic_user_id\` on \`builders\`
228
- - Every GDS API call from a Claude Code session includes \`X-Anthropic-User\` header; server cross-checks against stored value
229
-
230
- **Done when:**
231
- - Setup refuses to proceed on email mismatch
232
- - builders.anthropic_email + anthropic_user_id columns exist (migration)
233
- - API middleware verifies header on every authenticated route
234
- - Smoke: forge the header → 403 \`{error: 'identity_mismatch'}\`
235
- - V4 follow-up task filed: "Replace attestation with Anthropic OAuth when available"
236
-
237
- **Cross-refs:** C3. Touches setup.js, db.js, auth.js. File V4 task as a child idea.`,
238
- kind: 'feature',
239
- discipline: 'engineering',
240
- priority: 5,
241
- est_minutes: 240,
242
- manual_degree: 3,
243
- credits_reward: 45,
244
- touches: ['scripts/gds/setup.js', 'src/bongos/auth.js', 'src/bongos/db.js', 'migrations/'],
245
- },
246
-
247
- {
248
- ref: 'R11',
249
- title: 'Authorship attribution audit — exhaustive sweep for hardcoded "lars", "lars589", "lars@", paths, ids',
250
- description: `**Criterion:** C3 — per-builder authorship; C7 — server-enforced (not file-baked).
251
-
252
- **Why:** A second builder shipping code that says "by lars" in commits or "lars's machine" in error messages destroys the audit trail. Every hardcoded reference to the original Archon must be replaced by a lookup against the current builder's identity.
253
-
254
- **Done when:**
255
- - Grep sweep over the entire repo for: \`lars\`, \`lars589\`, \`lars@\`, \`larskristensen\`, \`/Users/lars\`, hardcoded \`builder_id=1\`, \`shipped_by=1\`
256
- - Every hit categorized: (a) replace with dynamic lookup, (b) keep as historical reference (e.g., session-log archives), (c) replace with placeholder
257
- - A \`scripts/gds/audit-authorship.sh\` script that re-runs the sweep and fails CI if new hardcodes show up
258
- - Documentation in CLAUDE.md says "no hardcoded Archon identity in implementation code; use \`req.builder\` / current-builder lookup"
259
-
260
- **Cross-refs:** Companion to R07. Runs after R01 (GDS rename) so paths reflect new layout.`,
261
- kind: 'cleanup',
262
- discipline: 'engineering',
263
- priority: 5,
264
- est_minutes: 240,
265
- manual_degree: 2,
266
- credits_reward: 35,
267
- touches: ['scripts/', 'src/', 'public/', 'public-builders/', 'public-status/', '.claude/'],
268
- },
269
-
270
- {
271
- ref: 'R12',
272
- title: 'Builder primer doc — system basics so builders can prompt Claude productively',
273
- description: `**Criterion:** C1 — onboarding ≤ 2h.
274
-
275
- **Why:** A new Metic shouldn't read CLAUDE.md cold (it's the index for AI agents, not a humans-first onboarding doc). The primer is the doc they read alongside Claude on day one, designed to give Claude enough seed context to answer questions.
276
-
277
- **Done when:**
278
- - File at \`docs/onboarding/primer.md\` covers (concise, ~2000 words):
279
- - What Off the Boats is (the game) — one paragraph
280
- - What the GDS is (the dev system) — one paragraph
281
- - The two tracks (product / internal)
282
- - The claim → ship lifecycle (with diagram)
283
- - The rank ladder (Xenos / Metic / Archon) + what each unlocks
284
- - Drachmae + karma (what they are, how they're earned)
285
- - "How to ask Claude about anything" — sample prompts
286
- - "Where to find more depth" — pointers to CLAUDE.md, ADRs, docs/recipes/
287
- - Newcomer skill or message points here on first session
288
- - Pairs with R76 (visual diagrams) for the picture-shaped version
289
-
290
- **Cross-refs:** C1. Read alongside R76 (diagrams) and the auto-completing checklist (R75).`,
291
- kind: 'feature',
292
- discipline: 'engineering',
293
- priority: 5,
294
- est_minutes: 180,
295
- manual_degree: 3,
296
- credits_reward: 30,
297
- touches: ['docs/onboarding/'],
298
- },
299
-
300
- {
301
- ref: 'R13',
302
- title: 'Onboarding observability + Archon-only builder management view in /builders hall',
303
- description: `**Criterion:** C1, C2 — onboarding visible to Archon; ranks managed from the hall.
304
-
305
- **Why:** Archon needs to see who's onboarding, where they are in the funnel, and act (promote, demote, release a stale claim) without dropping into psql.
306
-
307
- **Done when:**
308
- - builders table gets \`onboarded_at\` + \`first_ship_at\` columns (migration)
309
- - \`/builders\` hall renders an Archon-only management panel:
310
- - Roster of builders with current rank, drachmae, karma, onboarded_at, first_ship_at, time-to-first-ship
311
- - Per-builder actions: promote, demote, release-active-claim
312
- - Surface for stale claims (no pulse > 24h)
313
- - Calls into PATCH /builders/:id/rank (R06) and a new endpoint for release-claim-on-behalf
314
-
315
- **Cross-refs:** Depends on R05+R06. Pairs with R16 (rank visible on profile/roster). Used by Archon to graduate Xenos → Metic during V3.`,
316
- kind: 'feature',
317
- discipline: 'engineering',
318
- priority: 5,
319
- est_minutes: 360,
320
- manual_degree: 2,
321
- credits_reward: 60,
322
- touches: ['public-builders/', 'src/bongos/routes/builders.js', 'src/bongos/db.js', 'migrations/'],
323
- },
324
-
325
- {
326
- ref: 'R14',
327
- title: 'tasks.newcomer_friendly column + view filter + Xenos claim policy',
328
- description: `**Criterion:** C1 — newcomers always have something to claim. C2 — Xenos rank gates them down.
329
-
330
- **Why:** Xenos shouldn't be able to claim arbitrary tasks (they could break things they don't understand). Newcomer-friendly tasks are explicitly marked safe-for-newcomers, low-stakes, well-scoped.
331
-
332
- **Done when:**
333
- - \`tasks.newcomer_friendly bool DEFAULT false\` (migration)
334
- - \`claimable_tasks\` view: Xenos sees only \`newcomer_friendly = true\`; Metic+ sees all
335
- - POST /tasks accepts \`newcomer_friendly\` boolean
336
- - Server-side enforcement on POST /claims: reject Xenos claim of non-newcomer-friendly task with 403 \`{error: 'rank_too_low_for_task'}\`
337
- - Tag at least 3 currently-open backlog tasks as newcomer-friendly so the queue isn't empty when Xenos arrives
338
-
339
- **Cross-refs:** Depends on R04. Feeds R78 (auto-generator for newcomer tasks).`,
340
- kind: 'feature',
341
- discipline: 'engineering',
342
- priority: 5,
343
- est_minutes: 120,
344
- manual_degree: 2,
345
- credits_reward: 20,
346
- touches: ['migrations/', 'src/bongos/db.js', 'src/bongos/routes/tasks.js', 'src/bongos/routes/claims.js'],
347
- },
348
-
349
- {
350
- ref: 'R16',
351
- title: '/builders hall — rank visible on profile + roster + leaderboard',
352
- description: `**Criterion:** C2 — three ranks visible.
353
-
354
- **Why:** Rank needs to be readable at a glance throughout the hall, not buried in JSON.
355
-
356
- **Done when:**
357
- - Profile page shows current rank with a styled badge (Xenos = bronze, Metic = silver, Archon = gold; pick something Mediterranean-ish)
358
- - Roster lists rank next to each builder
359
- - Leaderboard sortable by rank
360
- - Mobile-friendly truncation
361
-
362
- **Cross-refs:** Depends on R04. Cheap UI task; can ship in parallel with R13.`,
363
- kind: 'feature',
364
- discipline: 'engineering',
365
- priority: 5,
366
- est_minutes: 60,
367
- manual_degree: 2,
368
- credits_reward: 10,
369
- touches: ['public-builders/'],
370
- },
371
-
372
- {
373
- ref: 'R17',
374
- title: 'V3 hello-world smoke — one real Metic onboards → claims → ships independently',
375
- description: `**Criterion:** the proof Tier 1 is done.
376
-
377
- **Why:** Tier 1 is "Builder #2 can ship without Archon's help." This task is the live exercise that proves it. Failure → file follow-up tasks. Success → graduate Builder #2 from Xenos to Metic for real.
378
-
379
- **Done when:**
380
- - A real human (Builder #2, identified by Archon at session time) clones the repo on a fresh machine, runs \`./scripts/setup-builder.sh\`, runs \`/builder-setup\`, hits \`/builder-start\`, claims a newcomer-friendly task, ships it
381
- - Total elapsed time from "Archon promoted you" to "your task is shipped on main" ≤ 2 hours
382
- - Friction points captured as GDS tasks for V3 (do not punt to V4)
383
- - Session log written: \`docs/session-logs/2026-MM-DD-v3-hello-world-with-<builder>.md\`
384
-
385
- **Cross-refs:** This is the C1 proof. Block on R07, R08, R12, R13, R14, R16 being live in prod.`,
386
- kind: 'spike',
387
- discipline: 'engineering',
388
- priority: 5,
389
- est_minutes: 120,
390
- manual_degree: 4,
391
- credits_reward: 30,
392
- touches: ['docs/session-logs/'],
393
- },
394
-
395
- // =========================================================================
396
- // TIER 2 — Quality + voice (P5). So Builder #2's first ship is judged and
397
- // they can speak up.
398
- // =========================================================================
399
-
400
- {
401
- ref: 'R22',
402
- title: 'Failed-confirmation feedback flow — write rejection reasons into learnings table',
403
- description: `**Criterion:** C4 — quality bar holds with N builders.
404
-
405
- **Why:** When the Opus grader rejects a confirmation, the builder needs structured feedback ("here's what failed, here's how to retry"), and the SYSTEM needs to learn from the rejection — not just the builder. Writing every rejection to the \`learnings\` table means future grader runs can see prior failures.
406
-
407
- **Done when:**
408
- - On every grader rejection, a row inserts into \`learnings\` with source=\`grader_rejection\`, source_ref=task_id, body containing the rubric scores + the specific failure
409
- - Builder gets a clean rendered message via \`/builder-ship\` response: "Confirmation failed — see learnings/<id> for details"
410
- - Tags include the failed criterion (e.g. \`tags: ['grader_rejection', 'value_summary_too_short']\`)
411
- - Cap rejections-per-task to prevent learning-spam if a task fails 10x
412
-
413
- **Cross-refs:** Depends on R18 (grader replacement). Feeds the calibration loop in R20 + R74.`,
414
- kind: 'feature',
415
- discipline: 'engineering',
416
- priority: 5,
417
- est_minutes: 180,
418
- manual_degree: 2,
419
- credits_reward: 30,
420
- touches: ['src/bongos/grader.js', 'src/bongos/learnings.js', 'src/bongos/routes/claims.js'],
421
- },
422
-
423
- {
424
- ref: 'R23',
425
- title: 'version_lifecycle_breakdown view double-counts parent tasks — fix',
426
- description: `**Criterion:** C4 — quality bar holds; correctness.
427
-
428
- **Why:** The view rolls up parent + child status independently, so a parent with 3 shipped children shows up as both "1 parent shipped" and "3 children shipped" — distorting the leaderboard and version-progress numbers as soon as parent/child tasks appear in V3.
429
-
430
- **Done when:**
431
- - Migration adds a new view that counts only leaf tasks, identical to how \`version_progress\` already does it
432
- - Old view either dropped or replaced
433
- - Status-page numbers for V3 match \`SELECT COUNT(*) FROM tasks WHERE version_id='GDS-V3' AND parent_task_id IS NULL\`
434
- - Regression test added that creates a parent + 2 children, ships both children, and asserts the rollup is correct
435
-
436
- **Cross-refs:** Promotes idea_inbox #15. Source: overnight-code-review run 2026-05-11.`,
437
- kind: 'bug',
438
- discipline: 'engineering',
439
- priority: 5,
440
- est_minutes: 90,
441
- manual_degree: 2,
442
- credits_reward: 15,
443
- touches: ['migrations/'],
444
- promoted_idea_id: 15,
445
- },
446
-
447
- {
448
- ref: 'R24',
449
- title: 'builders.karma + karma_log table — internal good-citizenship reputation track',
450
- description: `**Criterion:** C2 — three ranks + karma alongside drachmae.
451
-
452
- **Why:** Drachmae rewards work shipped (objective). Karma rewards good citizenship (subjective): voting fairly, surfacing useful ideas, helping newcomers, getting proposals ratified. Separate track so builders can see "I'm a productive shipper" vs "I'm a great teammate" as distinct signals.
453
-
454
- **Done when:**
455
- - Migration adds \`builders.karma integer NOT NULL DEFAULT 0\`
456
- - New table \`karma_log (id, builder_id, delta, reason text, recorded_at, granted_by builder_id NULL)\` — mirrors credit_log shape
457
- - Trigger or AFTER INSERT bumps builders.karma on every karma_log row
458
- - \`/api/gds/me\` returns karma
459
- - Initial reasons: \`peer_upvote\`, \`peer_downvote\`, \`proposal_ratified\`, \`archon_grant\` (V4 will add \`claude_interaction_signal\`, \`player_upvote\`)
460
-
461
- **Cross-refs:** Foundation for R25 (voting UI), R28 (boost on ratification). V4 idea filed for tone/intent reads + player voting.`,
462
- kind: 'feature',
463
- discipline: 'engineering',
464
- priority: 5,
465
- est_minutes: 120,
466
- manual_degree: 2,
467
- credits_reward: 20,
468
- touches: ['migrations/', 'src/bongos/db.js', 'src/bongos/routes/me.js'],
469
- },
470
-
471
- {
472
- ref: 'R25',
473
- title: 'Builder-on-builder upvote/downvote on confirmed work — UI + endpoint + anti-self-vote',
474
- description: `**Criterion:** C2 — karma signal sourcing.
475
-
476
- **Why:** Karma needs a continuous input from peers. Every confirmed task can be voted on by other Metics+; +1 = good work, -1 = concerns. Vote totals translate to karma changes for the shipping builder (e.g., +1 karma per net upvote at week-close).
477
-
478
- **Done when:**
479
- - New table \`peer_votes (id, voter_builder_id, target_task_id, vote int CHECK (-1, 1), recorded_at, UNIQUE(voter, target))\`
480
- - POST /api/gds/tasks/:id/vote { vote: 1 | -1 | 0 } — 0 to clear
481
- - Anti-self-vote: 403 if voter_id == task.shipped_by
482
- - /builders hall: every confirmed task in the feed gets a vote widget
483
- - Weekly cron tallies votes → karma_log entries; visible audit trail
484
- - Display: net votes on the task; karma updates lag by 7 days to discourage retaliation cycles
485
-
486
- **Cross-refs:** Depends on R24. Feeds R26 (surface on profile).`,
487
- kind: 'feature',
488
- discipline: 'engineering',
489
- priority: 5,
490
- est_minutes: 300,
491
- manual_degree: 2,
492
- credits_reward: 50,
493
- touches: ['migrations/', 'src/bongos/routes/tasks.js', 'public-builders/'],
494
- },
495
-
496
- {
497
- ref: 'R26',
498
- title: 'Karma surfaced on builder profile + sortable on leaderboard',
499
- description: `**Criterion:** C2.
500
-
501
- **Why:** Once R24+R25 are live, karma must be visible alongside drachmae. Builders should see their own karma trend + sort the leaderboard by karma instead of drachmae.
502
-
503
- **Done when:**
504
- - Profile page shows current karma + 30-day delta + recent karma_log entries
505
- - Leaderboard has a "sort by karma" toggle
506
- - Mobile-friendly
507
- - Tooltip on the karma badge explains the difference (drachmae = work shipped, karma = good citizenship)
508
-
509
- **Cross-refs:** Depends on R24.`,
510
- kind: 'feature',
511
- discipline: 'engineering',
512
- priority: 5,
513
- est_minutes: 90,
514
- manual_degree: 2,
515
- credits_reward: 15,
516
- touches: ['public-builders/'],
517
- },
518
-
519
- {
520
- ref: 'R27',
521
- title: 'Kind multipliers + staged idea-bonus (drachmae weighting per task kind)',
522
- description: `**Criterion:** C5 — builder voice; reward shape.
523
-
524
- **Why:** All credits_reward values today are treated equally regardless of task kind. GDS-V3 should over-reward the kinds we want more of: ideas that get promoted, learnings captured, bugs found in code review, blocker-resolutions. Under-reward routine maintenance.
525
-
526
- **Done when:**
527
- - Multiplier table (configurable): feature=1.0, bug=1.2, learning-capture=1.5, blocker-resolution=1.5, decision=1.3, infra=1.0, refactor=0.9, cleanup=0.8, spike=1.1
528
- - On ship, credits_reward is multiplied by the kind multiplier; credit_log row shows raw × multiplier in description
529
- - Staged idea-bonus: when an idea is promoted to a task and that task ships, the idea's original author gets a slice (e.g., 25% of credits_reward)
530
- - ADR documents the multiplier rationale
531
-
532
- **Cross-refs:** Promotes idea_inbox #6. Pairs with R32 (criterion-proposal workflow) — proposing builders earn karma + a slice when promoted.`,
533
- kind: 'feature',
534
- discipline: 'engineering',
535
- priority: 5,
536
- est_minutes: 240,
537
- manual_degree: 2,
538
- credits_reward: 40,
539
- touches: ['src/bongos/db.js', 'src/bongos/ship.js', 'migrations/', 'docs/adr/'],
540
- promoted_idea_id: 6,
541
- },
542
-
543
- {
544
- ref: 'R28',
545
- title: 'Karma boost on proposal ratification (cross-link C5 → C2)',
546
- description: `**Criterion:** C5, C2.
547
-
548
- **Why:** When Archon ratifies a Metic's proposal into a real criterion or task, the Metic gets karma (good citizenship signal). Pure mechanism — fires inside the ratification flow.
549
-
550
- **Done when:**
551
- - The ratification endpoint (from R32) writes a karma_log row for the proposing builder on success
552
- - Reason: \`proposal_ratified\`
553
- - Delta: +3 (tunable)
554
- - Visible in the proposer's karma feed
555
-
556
- **Cross-refs:** Depends on R24, R32.`,
557
- kind: 'feature',
558
- discipline: 'engineering',
559
- priority: 5,
560
- est_minutes: 30,
561
- manual_degree: 1,
562
- credits_reward: 5,
563
- touches: ['src/bongos/inbox.js', 'src/bongos/db.js'],
564
- },
565
-
566
- {
567
- ref: 'R29',
568
- title: 'Promotion/demotion ceremony — credit_log + chat broadcast + Claude SessionStart welcome',
569
- description: `**Criterion:** C2 — three ranks are real, not just a column flip.
570
-
571
- **Why:** Rank changes should feel like ceremony, not bureaucracy. Three signals fire on every promotion or demotion: ledger (credit_log row, +5c for promotion, 0 for demotion with note), team chat (broadcast in tone-appropriate Mediterranean prose), Claude (SessionStart hook detects rank-change-since-last-session and the agent's first reply honors them).
572
-
573
- **Done when:**
574
- - Rank-change endpoint writes a credit_log row \`reason='rank_change'\` with bonus on promotion, audit-only on demotion
575
- - Chat broadcast (post.js wrapper) named role: "Citizens of Amazonprimea — <name> has been raised to the rank of <rank>."
576
- - SessionStart hook (\`scripts/chat/poll.js\` equivalent) checks for unread rank changes on the current builder; if present, writes a one-liner to a transient file that Claude reads on session start
577
- - Tone is celebratory for promotions, dignified for demotions (no shaming)
578
-
579
- **Cross-refs:** Depends on R06. Cross-link to R28 (karma on ratification — same ceremony pattern).`,
580
- kind: 'feature',
581
- discipline: 'engineering',
582
- priority: 5,
583
- est_minutes: 180,
584
- manual_degree: 2,
585
- credits_reward: 25,
586
- touches: ['src/bongos/routes/builders.js', 'scripts/chat/', '.claude/hooks/'],
587
- },
588
-
589
- {
590
- ref: 'R30',
591
- title: 'Rank-gate /idea-triage skill to Metic+',
592
- description: `**Criterion:** C5 — builder voice (Metic+ runs triage, not just Archon).
593
-
594
- **Why:** Triage shouldn't be Archon-only. Trusted builders should be able to triage the idea_inbox (promote / discard / merge / defer).
595
-
596
- **Done when:**
597
- - \`.claude/skills/idea-triage/SKILL.md\` opening check calls \`/api/gds/me\` and refuses if rank < Metic with a clear message
598
- - Server-side: PATCH /inbox/:id enforces requireRank('Metic')
599
- - Smoke: Xenos opens /idea-triage → "this skill requires Metic+; please ask Archon for promotion"; Metic opens → works
600
-
601
- **Cross-refs:** Depends on R05.`,
602
- kind: 'feature',
603
- discipline: 'engineering',
604
- priority: 5,
605
- est_minutes: 60,
606
- manual_degree: 2,
607
- credits_reward: 10,
608
- touches: ['.claude/skills/idea-triage/', 'src/bongos/routes/inbox.js'],
609
- },
610
-
611
- {
612
- ref: 'R31',
613
- title: 'Rank-gate /blocker-review skill to Metic+',
614
- description: `**Criterion:** C5.
615
-
616
- **Why:** Same pattern as R30 — Metics should be able to walk open blockers and resolve / escalate.
617
-
618
- **Done when:**
619
- - \`.claude/skills/blocker-review/SKILL.md\` enforces Metic+
620
- - Server-side: PATCH /blockers/:id enforces requireRank('Metic')
621
- - Smoke test
622
-
623
- **Cross-refs:** Depends on R05.`,
624
- kind: 'feature',
625
- discipline: 'engineering',
626
- priority: 5,
627
- est_minutes: 45,
628
- manual_degree: 2,
629
- credits_reward: 8,
630
- touches: ['.claude/skills/blocker-review/', 'src/bongos/routes/blockers.js'],
631
- },
632
-
633
- {
634
- ref: 'R32',
635
- title: 'idea_inbox.kind=\'criterion-proposal\' workflow + ratification audit log',
636
- description: `**Criterion:** C5 — Metics propose, Archon ratifies.
637
-
638
- **Why:** Metics need a place to drop proposed criteria and tasks for the next version that's separate from random ideas. Add a new \`kind\` value and a ratification flow that promotes a criterion-proposal into a real done_when_criteria row.
639
-
640
- **Done when:**
641
- - \`idea_inbox.kind\` now accepts \`'criterion-proposal'\`
642
- - Planning-session skill (Metic mode) writes proposals here with structure: \`{ target_version, criterion_md, sort_order_hint }\` in body_md
643
- - New endpoint POST /api/gds/inbox/:id/ratify (Archon-only) — atomically inserts a done_when_criteria row + marks idea promoted + writes karma_log for proposer
644
- - Audit log row captures: who proposed, who ratified, when, what idea_id, what criterion_id
645
-
646
- **Cross-refs:** Depends on R02 (or already-shipped R32 via planning-session skill from V3.R00). Cross-link to R28 (karma boost).`,
647
- kind: 'feature',
648
- discipline: 'engineering',
649
- priority: 5,
650
- est_minutes: 240,
651
- manual_degree: 2,
652
- credits_reward: 40,
653
- touches: ['src/bongos/inbox.js', 'src/bongos/done-when.js', 'src/bongos/routes/inbox.js', 'migrations/'],
654
- },
655
-
656
- // =========================================================================
657
- // TIER 3 — Security foundations + observability (P4). Parallelizable.
658
- // =========================================================================
659
-
660
- {
661
- ref: 'R33',
662
- title: 'docs/security-baseline.md — checklist that must be green before any non-Archon ships',
663
- description: `**Criterion:** C9 — security baseline.
664
-
665
- **Why:** Before Builder #2 ships, a checklist exists that says "these basics are in place." It's not a moat — it's a floor.
666
-
667
- **Done when:**
668
- - File at \`docs/security-baseline.md\` enumerates: input validation per write route, auth-token hygiene, rate limits, audit logging, dep-scan in CI, no secrets in repo, observability dashboards
669
- - Each item links to the implementing task (R34–R44)
670
- - A meta-check script \`scripts/gds/security-baseline-check.sh\` re-verifies each item programmatically (curl the endpoints, grep CI for the scan step, etc.)
671
- - /merge-mode refuses to ship a non-Archon claim if the check script is not green
672
-
673
- **Cross-refs:** Umbrella for Tier 3. Block on R34-R44 to be fully green.`,
674
- kind: 'infra',
675
- discipline: 'engineering',
676
- priority: 4,
677
- est_minutes: 120,
678
- manual_degree: 2,
679
- credits_reward: 20,
680
- touches: ['docs/security-baseline.md', 'scripts/gds/security-baseline-check.sh'],
681
- },
682
-
683
- {
684
- ref: 'R34',
685
- title: 'Input validation pass on every GDS write endpoint',
686
- description: `**Criterion:** C9.
687
-
688
- **Why:** Today validation is uneven across routes. With multiple builders hitting the API, every write needs defensive input checks: type, range, length, allowed-values.
689
-
690
- **Done when:**
691
- - Each route file in \`src/bongos/routes/\` has explicit validation up front; bad input → 400 with structured error
692
- - Length caps on user-supplied text (title ≤ 200, description ≤ 50000, notes ≤ 10000)
693
- - Enum fields verified against in-code sets
694
- - Smoke test: every POST/PATCH/DELETE route hit with bad inputs; expect 400, not 500
695
-
696
- **Cross-refs:** Foundation for R35 (rate limits) + R65 (red-team target).`,
697
- kind: 'cleanup',
698
- discipline: 'engineering',
699
- priority: 4,
700
- est_minutes: 240,
701
- manual_degree: 2,
702
- credits_reward: 35,
703
- touches: ['src/bongos/routes/'],
704
- },
705
-
706
- {
707
- ref: 'R35',
708
- title: 'Rate limits on write paths — Caddy + Express middleware',
709
- description: `**Criterion:** C9.
710
-
711
- **Why:** A malicious or buggy builder script could hammer /api/gds/tasks at 1000/sec and crash the droplet. Rate-limit per session + per IP.
712
-
713
- **Done when:**
714
- - Caddy global rate-limit on /api/gds/* write methods (POST/PATCH/DELETE): 30/minute per IP
715
- - Express middleware (\`express-rate-limit\` or hand-rolled): 60/minute per authenticated session
716
- - 429 response with Retry-After header
717
- - Read paths uncapped
718
- - Smoke test hits the limit and verifies 429
719
-
720
- **Cross-refs:** Pairs with R36 (audit log of throttled attempts).`,
721
- kind: 'infra',
722
- discipline: 'engineering',
723
- priority: 4,
724
- est_minutes: 120,
725
- manual_degree: 2,
726
- credits_reward: 20,
727
- touches: ['infra/Caddyfile', 'src/bongos/middleware/', 'server.js'],
728
- },
729
-
730
- {
731
- ref: 'R36',
732
- title: 'audit_log table — every privileged write captured',
733
- description: `**Criterion:** C9 — security baseline; C7 — server-enforced (forensics).
734
-
735
- **Why:** Today most state changes are recoverable from individual tables (credit_log, task updates) but there's no single audit stream. With N builders, we need an append-only log of "who did what when" for security review + post-incident forensics.
736
-
737
- **Done when:**
738
- - Migration adds \`audit_log (id, builder_id, route, method, request_body_redacted jsonb, response_status int, ip, user_agent, recorded_at)\`
739
- - Middleware logs every authenticated write
740
- - Redaction: any field named \`token\`, \`password\`, \`key\`, \`secret\` is replaced with \`<redacted>\`
741
- - Read-only via API for Archon (R67 — Archon security view)
742
- - Retention: indefinite for V3; archive policy is V4
743
-
744
- **Cross-refs:** Feeds R67 (security view), R70 (weekly review).`,
745
- kind: 'feature',
746
- discipline: 'engineering',
747
- priority: 4,
748
- est_minutes: 240,
749
- manual_degree: 2,
750
- credits_reward: 40,
751
- touches: ['migrations/', 'src/bongos/middleware/audit.js', 'src/bongos/db.js'],
752
- },
753
-
754
- {
755
- ref: 'R37',
756
- title: 'Pre-commit secrets check + CI step',
757
- description: `**Criterion:** C9, C8 — no secrets in repo.
758
-
759
- **Why:** A builder commits an .env file by accident → secrets leak the moment they push. Catch it at commit-time (pre-commit hook) and at PR-time (CI check).
760
-
761
- **Done when:**
762
- - \`.husky/pre-commit\` (or equivalent) runs \`trufflehog\` or \`git-secrets\` against staged changes; aborts commit on hit
763
- - CI job runs full-history scan on PRs
764
- - Allowlist file for known false positives
765
- - README updated with "if pre-commit blocks your commit, here's how to investigate"
766
-
767
- **Cross-refs:** Pairs with R38 (dependency scan).`,
768
- kind: 'infra',
769
- discipline: 'engineering',
770
- priority: 4,
771
- est_minutes: 90,
772
- manual_degree: 2,
773
- credits_reward: 15,
774
- touches: ['.husky/', '.github/workflows/', 'README.md'],
775
- },
776
-
777
- {
778
- ref: 'R38',
779
- title: 'Dependency-scan in CI (npm audit + pip-audit) + nightly cron + alert on high-severity',
780
- description: `**Criterion:** C9.
781
-
782
- **Done when:**
783
- - CI job runs \`npm audit --audit-level=high\` + \`pip-audit\` against the Python art pipeline; PRs fail on high+
784
- - Nightly scheduled task on droplet runs the same; results posted to chat-inbox + Archon security view (R67) on hits
785
- - Cleanup of any currently-flagged high-severity deps as part of this task
786
-
787
- **Cross-refs:** Cross-link to R44 (rank-check audit cron pattern).`,
788
- kind: 'infra',
789
- discipline: 'engineering',
790
- priority: 4,
791
- est_minutes: 120,
792
- manual_degree: 2,
793
- credits_reward: 20,
794
- touches: ['.github/workflows/', 'scripts/security/', 'package.json', 'art/requirements.txt'],
795
- },
796
-
797
- {
798
- ref: 'R39',
799
- title: 'Auth token hygiene — short-lived sessions, refresh-on-use, revocation endpoint',
800
- description: `**Criterion:** C9, C7 — rank changes must propagate fast.
801
-
802
- **Why:** Today tokens are long-lived. For rank-change-near-instant (C7), tokens need a short TTL with refresh-on-use, and Archon needs a way to revoke any session.
803
-
804
- **Done when:**
805
- - Sessions TTL drops from existing value to 1 hour
806
- - Every authenticated request refreshes \`builder_sessions.last_used_at\`; expiry recomputed
807
- - POST /api/gds/auth/revoke (Archon-only) — kill a session by id
808
- - POST /api/gds/auth/revoke-all (Archon-only) — kill every session for a builder (use on demotion)
809
- - Demotion endpoint (R06) calls revoke-all on the demoted builder
810
- - Smoke test: revoke a session → next API call → 401
811
-
812
- **Cross-refs:** Foundation of "near-instant rank change" — pairs with R44/R45 (rank check on every request).`,
813
- kind: 'feature',
814
- discipline: 'engineering',
815
- priority: 4,
816
- est_minutes: 180,
817
- manual_degree: 2,
818
- credits_reward: 30,
819
- touches: ['src/bongos/auth.js', 'src/bongos/db.js', 'migrations/'],
820
- },
821
-
822
- {
823
- ref: 'R40',
824
- title: 'Staging environment — provision staging.amazonprimea.com (separate subdomain, DB, Origin Cert SAN)',
825
- description: `**Criterion:** C9 — staging mirrors prod; red-team target.
826
-
827
- **Why:** Production cannot be the red-team target. Staging is the controlled mirror where builders can try to break things.
828
-
829
- **Done when:**
830
- - DNS A record for staging.amazonprimea.com (Cloudflare-proxied)
831
- - Cloudflare Origin Cert reissued with \`*.amazonprimea.com\` SAN (already covers it; verify)
832
- - Caddy site block for staging.amazonprimea.com → 127.0.0.1:3001
833
- - New systemd unit \`amazonprimea-staging.service\` running the staging branch on port 3001
834
- - Separate Postgres database \`amazonprimea_staging\`
835
- - Separate env file with staging-specific keys
836
- - HTTPS smoke: curl https://staging.amazonprimea.com/healthz → 200
837
-
838
- **Cross-refs:** Heaviest single piece in V3. Block on R41 (deploy automation) + R42 (data seed) for the staging environment to be useful.`,
839
- kind: 'infra',
840
- discipline: 'engineering',
841
- priority: 4,
842
- est_minutes: 480,
843
- manual_degree: 4,
844
- credits_reward: 80,
845
- touches: ['infra/', 'scripts/deploy/'],
846
- },
847
-
848
- {
849
- ref: 'R41',
850
- title: 'Staging deploy automation — ~/deploy-staging.sh + branch convention',
851
- description: `**Criterion:** C9.
852
-
853
- **Why:** Builders should be able to push to staging without touching prod.
854
-
855
- **Done when:**
856
- - Convention: branch \`staging\` is auto-deployed to staging.amazonprimea.com on push
857
- - ~/deploy-staging.sh script on droplet mirrors ~/deploy.sh structure (git pull, npm ci, migrate against staging DB, restart staging service, smoke)
858
- - GitHub workflow on push-to-staging triggers SSH deploy
859
- - Smoke: push commit to staging branch → staging.amazonprimea.com reflects it within 2 minutes
860
-
861
- **Cross-refs:** Depends on R40.`,
862
- kind: 'infra',
863
- discipline: 'engineering',
864
- priority: 4,
865
- est_minutes: 240,
866
- manual_degree: 3,
867
- credits_reward: 40,
868
- touches: ['scripts/deploy/', '.github/workflows/'],
869
- },
870
-
871
- {
872
- ref: 'R42',
873
- title: 'Staging data seeding — anonymized prod snapshot or fixture seed',
874
- description: `**Criterion:** C9.
875
-
876
- **Done when:**
877
- - Script \`scripts/gds/seed-staging.sh\` pulls a fresh anonymized snapshot of prod into staging (or seeds from a fixture file if anonymization is too costly)
878
- - Anonymization: replace builder GitHub logins with \`builder-N\`; nuke real chat-inbox content; preserve task/cost/credit row structure
879
- - Reseeded weekly via cron OR on demand by Archon
880
- - Documentation: "what's real, what's faked, on staging"
881
-
882
- **Cross-refs:** Depends on R40 + R41.`,
883
- kind: 'infra',
884
- discipline: 'engineering',
885
- priority: 4,
886
- est_minutes: 180,
887
- manual_degree: 3,
888
- credits_reward: 30,
889
- touches: ['scripts/gds/seed-staging.sh', 'docs/'],
890
- },
891
-
892
- {
893
- ref: 'R43',
894
- title: 'Observability dashboard — Grafana provisioned-as-code (dashboards JSON in repo)',
895
- description: `**Criterion:** C9 — pulled forward from V4 because the public launch needs eyes.
896
-
897
- **Why:** When 5 builders are hitting prod and the public is watching, you need a single screen that shows: error rate per route, auth-failure spikes, system load, per-builder activity, claim/ship rates.
898
-
899
- **Done when:**
900
- - Prometheus exporter on the Node process (\`/metrics\` endpoint with default metrics + custom counters for ship rate, claim rate, auth fails, 4xx/5xx per route)
901
- - Grafana self-hosted on droplet (~150 MB RAM), reverse-proxied at metrics.amazonprimea.com (Archon-only, Cloudflare Access or basic auth)
902
- - All dashboards stored as JSON in \`infra/grafana/dashboards/\` — provisioned via Grafana's file-based config, NOT drag-and-drop. Editable in VS Code, version-controlled
903
- - Initial dashboards: System Overview, Error Watch, Builder Activity, Auth + Security
904
-
905
- **Cross-refs:** Cross-link to R36 (audit_log feeds the security dashboard).`,
906
- kind: 'infra',
907
- discipline: 'engineering',
908
- priority: 4,
909
- est_minutes: 480,
910
- manual_degree: 3,
911
- credits_reward: 80,
912
- touches: ['infra/grafana/', 'infra/prometheus/', 'src/bongos/metrics.js', 'server.js'],
913
- },
914
-
915
- {
916
- ref: 'R44',
917
- title: 'Rank-check audit pass on every route in src/bongos/routes/',
918
- description: `**Criterion:** C7 — server-enforced.
919
-
920
- **Why:** The output of R02 (the spike) defines what level of rank each route requires. This task is the implementation: go route by route, attach the right \`requireRank\` call, document why.
921
-
922
- **Done when:**
923
- - Every route in src/bongos/routes/ is annotated with a \`// rank: <level>\` comment + the actual middleware call
924
- - Routes that don't need auth at all (public/) are annotated \`// rank: public\`
925
- - A \`docs/routes-permissions.md\` is auto-generated from the annotations
926
- - Smoke test: hit every Metic+ route as Xenos → 403
927
- - Cross-reference with R45 (periodic auditor) so drift is caught
928
-
929
- **Cross-refs:** Depends on R02 + R05.`,
930
- kind: 'cleanup',
931
- discipline: 'engineering',
932
- priority: 4,
933
- est_minutes: 240,
934
- manual_degree: 2,
935
- credits_reward: 35,
936
- touches: ['src/bongos/routes/', 'docs/routes-permissions.md'],
937
- },
938
-
939
- {
940
- ref: 'R45',
941
- title: 'Periodic rank-check auditor — nightly scheduled task, files an idea on drift',
942
- description: `**Criterion:** C7 — drift detection.
943
-
944
- **Why:** Manual audits drift. A nightly job re-greps every route and compares against the canonical list (from R44); any mismatch files an idea_inbox row tagged \`drift_rank_check\`.
945
-
946
- **Done when:**
947
- - Scheduled task in \`.claude/scheduled-tasks/rank-check-audit/\`
948
- - Cron: nightly at 03:00 America/New_York
949
- - On mismatch: files idea_inbox row with details + diff
950
- - On clean run: silent (no inbox noise)
951
- - Wired into the scheduled-tasks MCP
952
-
953
- **Cross-refs:** Depends on R44.`,
954
- kind: 'infra',
955
- discipline: 'engineering',
956
- priority: 4,
957
- est_minutes: 120,
958
- manual_degree: 2,
959
- credits_reward: 20,
960
- touches: ['.claude/scheduled-tasks/rank-check-audit/'],
961
- },
962
-
963
- // =========================================================================
964
- // TIER 4 — Parallel safety + memory infra (P4).
965
- // =========================================================================
966
-
967
- {
968
- ref: 'R48',
969
- title: 'Touches[] verification at PR merge time (not just at ship)',
970
- description: `**Criterion:** C6 — parallel safety.
971
-
972
- **Why:** Today the touches[] scanner runs at \`/builder-ship\`, but with multiple builders merging PRs, drift could land on main before scanner sees it. Run it again at PR merge.
973
-
974
- **Done when:**
975
- - GitHub Action on PR merge: clones the branch, runs \`scripts/gds/touches-scan.js\` against the PR's claim's touches[], blocks the merge on drift
976
- - Builder gets a structured comment explaining what drifted
977
- - /merge-mode skill aware of this — won't re-attempt blocked merges
978
-
979
- **Cross-refs:** Promotes idea_inbox #2.`,
980
- kind: 'feature',
981
- discipline: 'engineering',
982
- priority: 4,
983
- est_minutes: 180,
984
- manual_degree: 2,
985
- credits_reward: 30,
986
- touches: ['.github/workflows/', 'scripts/gds/touches-scan.js'],
987
- promoted_idea_id: 2,
988
- },
989
-
990
- {
991
- ref: 'R49',
992
- title: 'Auto-detect migrations/ sentinel from task title or description',
993
- description: `**Criterion:** C6, C1 — fewer builder mistakes.
994
-
995
- **Why:** Today builders must remember to add \`migrations/\` to touches[] when their task involves a schema change. Forgetting it = scanner doesn't reserve a migration number. Auto-detect from "migration" / "schema" / "alter table" / "create table" keywords in title/description and append automatically.
996
-
997
- **Done when:**
998
- - POST /api/gds/tasks server-side: if title or description matches the keyword set AND \`migrations/\` not in touches, append it (with a flag on the response: \`migrations_auto_added: true\`)
999
- - Same logic in capture.js for parity
1000
- - Builders can opt out by passing \`{auto_detect_touches: false}\`
1001
-
1002
- **Cross-refs:** Promotes idea_inbox #3.`,
1003
- kind: 'feature',
1004
- discipline: 'engineering',
1005
- priority: 4,
1006
- est_minutes: 60,
1007
- manual_degree: 2,
1008
- credits_reward: 10,
1009
- touches: ['src/bongos/routes/tasks.js', 'scripts/gds/capture.js'],
1010
- promoted_idea_id: 3,
1011
- },
1012
-
1013
- {
1014
- ref: 'R50',
1015
- title: 'Stale-claim auto-release via session_pulses heartbeat',
1016
- description: `**Criterion:** C6.
1017
-
1018
- **Why:** A builder claims a task, their machine dies, the claim sits forever. \`session_pulses\` exists (PMS-V2); add the auto-release logic.
1019
-
1020
- **Done when:**
1021
- - Scheduled task every 15 minutes: any claim with no pulse in 6 hours → released with outcome='abandoned-stale', no credits, log entry
1022
- - Builder gets a chat-broadcast ping if their claim was auto-released
1023
- - Configurable threshold (env var or admin endpoint)
1024
-
1025
- **Cross-refs:** Pairs with R45.`,
1026
- kind: 'feature',
1027
- discipline: 'engineering',
1028
- priority: 4,
1029
- est_minutes: 120,
1030
- manual_degree: 2,
1031
- credits_reward: 20,
1032
- touches: ['scripts/gds/pulse.js', '.claude/scheduled-tasks/'],
1033
- },
1034
-
1035
- {
1036
- ref: 'R51',
1037
- title: 'Merge serialization audit — find "I am the only builder" assumptions in ship.js + /merge-mode',
1038
- description: `**Criterion:** C6.
1039
-
1040
- **Why:** Existing flows likely assume single-builder ops (e.g., one worktree, one git fetch racing nobody). Audit + add concurrency guards.
1041
-
1042
- **Done when:**
1043
- - Audit doc: \`docs/recipes/multi-builder-merge.md\` lists every shared-state surface, every place where ship.js or /merge-mode assumes serialized access, every git operation that could race
1044
- - Critical issues filed as new tasks
1045
- - Optimistic concurrency control (or a lightweight mutex) added where needed
1046
-
1047
- **Cross-refs:** Cross-link to R54 (parallel-load smoke).`,
1048
- kind: 'spike',
1049
- discipline: 'engineering',
1050
- priority: 4,
1051
- est_minutes: 180,
1052
- manual_degree: 3,
1053
- credits_reward: 30,
1054
- touches: ['scripts/gds/ship.js', '.claude/skills/merge-mode/', 'docs/recipes/'],
1055
- },
1056
-
1057
- {
1058
- ref: 'R52',
1059
- title: 'Per-builder worktree-name collision check + auto-disambiguation',
1060
- description: `**Criterion:** C6.
1061
-
1062
- **Why:** \`.claude/worktrees/<random>\` should never collide across 5 builders, but verify + add a server-side uniqueness check on POST /api/gds/claims.
1063
-
1064
- **Done when:**
1065
- - POST /api/gds/claims includes worktree_name in the uniqueness key (server-side check)
1066
- - Two claims with the same worktree_name → second one auto-disambiguated with a suffix
1067
- - Test: simulate parallel claim with same worktree_name → both succeed with distinct names
1068
-
1069
- **Cross-refs:** Cheap; pairs with R54.`,
1070
- kind: 'feature',
1071
- discipline: 'engineering',
1072
- priority: 4,
1073
- est_minutes: 60,
1074
- manual_degree: 2,
1075
- credits_reward: 10,
1076
- touches: ['src/bongos/routes/claims.js', 'src/bongos/db.js'],
1077
- },
1078
-
1079
- {
1080
- ref: 'R53',
1081
- title: 'Audit-trail completeness check — forensic reconstructability per builder',
1082
- description: `**Criterion:** C6, C9.
1083
-
1084
- **Why:** Can we, given a builder_id and a date range, reconstruct everything they did? If not, the audit trail is incomplete.
1085
-
1086
- **Done when:**
1087
- - Script \`scripts/gds/audit-replay.sh <builder_id> <start> <end>\` outputs a chronological log of: every claim, every ship, every cost entry, every karma change, every audit_log row
1088
- - Gaps identified → filed as tasks
1089
- - Doc: \`docs/recipes/audit-replay.md\` describes how to use it
1090
-
1091
- **Cross-refs:** Depends on R36 (audit_log).`,
1092
- kind: 'infra',
1093
- discipline: 'engineering',
1094
- priority: 4,
1095
- est_minutes: 180,
1096
- manual_degree: 3,
1097
- credits_reward: 30,
1098
- touches: ['scripts/gds/', 'docs/recipes/'],
1099
- },
1100
-
1101
- {
1102
- ref: 'R54',
1103
- title: 'Parallel-load smoke test — simulate 5 builders claiming/shipping/merging on staging',
1104
- description: `**Criterion:** C6 — validates Tier 4.
1105
-
1106
- **Why:** All the parallel-safety hardening above means nothing if not exercised. Run a real load test against staging with 5 simulated builders.
1107
-
1108
- **Done when:**
1109
- - Test harness in \`tests/parallel-load.mjs\` spawns 5 concurrent "builder" sessions
1110
- - Each session: claim a task, simulate 5-min work, ship, claim another
1111
- - Run for 30 minutes against staging
1112
- - All claims either succeed or 409 (collision) cleanly; no 500s, no race conditions
1113
- - Output: per-second throughput, claim collision rate, any anomalies
1114
-
1115
- **Cross-refs:** Depends on R40-R42 (staging exists). Validates R48-R53.`,
1116
- kind: 'spike',
1117
- discipline: 'engineering',
1118
- priority: 4,
1119
- est_minutes: 240,
1120
- manual_degree: 3,
1121
- credits_reward: 40,
1122
- touches: ['tests/'],
1123
- },
1124
-
1125
- {
1126
- ref: 'R55',
1127
- title: 'builder_memory server-side store schema (output of R03 spike)',
1128
- description: `**Criterion:** C8.
1129
-
1130
- **Why:** Server-canonical per-builder memory; schema designed by R03.
1131
-
1132
- **Done when:**
1133
- - Migration adds the schema R03 recommended (Postgres BYTEA per-file vs object storage TBD)
1134
- - Helper functions: \`storeMemoryFile(builder_id, path, content)\`, \`fetchMemoryFile(builder_id, path)\`, \`listMemoryFiles(builder_id)\`
1135
- - Per-builder isolation enforced at the helper layer
1136
-
1137
- **Cross-refs:** Depends on R03 (spike).`,
1138
- kind: 'feature',
1139
- discipline: 'engineering',
1140
- priority: 4,
1141
- est_minutes: 180,
1142
- manual_degree: 2,
1143
- credits_reward: 30,
1144
- touches: ['migrations/', 'src/bongos/memory.js', 'src/bongos/db.js'],
1145
- },
1146
-
1147
- {
1148
- ref: 'R56',
1149
- title: 'Memory sync-on-ship — /builder-ship pushes builder\'s local memory dir',
1150
- description: `**Criterion:** C8.
1151
-
1152
- **Done when:**
1153
- - \`/builder-ship\` reads \`~/.claude/projects/.../memory/\` (or whatever Claude Code's current memory dir is on the builder's machine)
1154
- - Calls POST /api/gds/memory/sync with each file
1155
- - Server stores via R55's helpers
1156
- - Progress visible to the builder ("syncing 3 memory files…")
1157
-
1158
- **Cross-refs:** Depends on R55. Pairs with R57.`,
1159
- kind: 'feature',
1160
- discipline: 'engineering',
1161
- priority: 4,
1162
- est_minutes: 180,
1163
- manual_degree: 2,
1164
- credits_reward: 30,
1165
- touches: ['scripts/gds/ship.js', 'src/bongos/routes/memory.js'],
1166
- },
1167
-
1168
- {
1169
- ref: 'R57',
1170
- title: 'Memory pull-on-session-start — fresh worktree pulls server-side memory if newer',
1171
- description: `**Criterion:** C8.
1172
-
1173
- **Done when:**
1174
- - SessionStart hook (or \`/builder-start\`) checks server-side memory mtime
1175
- - Pulls any file newer than local
1176
- - Last-write-wins per the R03 policy
1177
- - Smoke: ship on machine A, pull on machine B → memory matches
1178
-
1179
- **Cross-refs:** Depends on R55, R56.`,
1180
- kind: 'feature',
1181
- discipline: 'engineering',
1182
- priority: 4,
1183
- est_minutes: 120,
1184
- manual_degree: 2,
1185
- credits_reward: 20,
1186
- touches: ['.claude/hooks/', 'scripts/gds/start.js'],
1187
- },
1188
-
1189
- {
1190
- ref: 'R58',
1191
- title: 'Per-builder memory isolation — server enforces no cross-builder reads',
1192
- description: `**Criterion:** C8, C9.
1193
-
1194
- **Done when:**
1195
- - Every memory endpoint asserts \`req.builder.id === path_owner_id\`
1196
- - Smoke: builder A's session reading builder B's memory → 403
1197
- - Archon override exists for forensics but is audit-logged
1198
-
1199
- **Cross-refs:** Depends on R55.`,
1200
- kind: 'feature',
1201
- discipline: 'engineering',
1202
- priority: 4,
1203
- est_minutes: 60,
1204
- manual_degree: 2,
1205
- credits_reward: 10,
1206
- touches: ['src/bongos/routes/memory.js'],
1207
- },
1208
-
1209
- {
1210
- ref: 'R59',
1211
- title: 'Memory conflict resolution policy doc',
1212
- description: `**Criterion:** C8.
1213
-
1214
- **Done when:**
1215
- - Doc at \`docs/recipes/memory-sync-conflicts.md\` describes the policy R03 chose (likely last-write-wins per file)
1216
- - Edge cases: builder edits same file in two parallel sessions, server has newer version than local
1217
- - Operator guidance: how to recover a clobbered file from backup (R63)
1218
-
1219
- **Cross-refs:** Depends on R03.`,
1220
- kind: 'feature',
1221
- discipline: 'engineering',
1222
- priority: 4,
1223
- est_minutes: 60,
1224
- manual_degree: 3,
1225
- credits_reward: 10,
1226
- touches: ['docs/recipes/'],
1227
- },
1228
-
1229
- {
1230
- ref: 'R60',
1231
- title: '.env.local propagation fix for git worktrees (known gotcha)',
1232
- description: `**Criterion:** C8 — onboarding shouldn't trip over this.
1233
-
1234
- **Why:** CLAUDE.md flags this: ".env.local does not propagate to git worktrees. Copy it from a sibling worktree before running anything that hits the Google API." This is a footgun for new builders.
1235
-
1236
- **Done when:**
1237
- - Post-worktree-create hook (or wrapper script) auto-copies .env.local from the main checkout into the new worktree
1238
- - If .env.local doesn't exist in main, prompts to run /builder-setup
1239
- - Documented as solved in CLAUDE.md (remove the warning)
1240
-
1241
- **Cross-refs:** Pairs with R08 (bootstrap script).`,
1242
- kind: 'cleanup',
1243
- discipline: 'engineering',
1244
- priority: 4,
1245
- est_minutes: 45,
1246
- manual_degree: 2,
1247
- credits_reward: 8,
1248
- touches: ['scripts/', '.claude/hooks/', 'CLAUDE.md'],
1249
- },
1250
-
1251
- {
1252
- ref: 'R61',
1253
- title: 'Secrets-in-repo scan + pre-commit hook (separate from R37 — broader policy)',
1254
- description: `**Criterion:** C8 — verified, not assumed.
1255
-
1256
- **Done when:**
1257
- - One-time historical scan with trufflehog over the entire repo history
1258
- - Any hits → rotated keys + filtered from history (BFG repo-cleaner or git filter-repo)
1259
- - Pre-commit hook from R37 catches future ones
1260
- - ADR \`docs/adr/0017-secrets-policy.md\` documents: what's a secret, where they live (\`/etc/amazonprimea/secret\` on droplet only), how rotation works
1261
-
1262
- **Cross-refs:** Depends on R37 (the hook). This task is the historical sweep + the policy.`,
1263
- kind: 'cleanup',
1264
- discipline: 'engineering',
1265
- priority: 4,
1266
- est_minutes: 180,
1267
- manual_degree: 3,
1268
- credits_reward: 30,
1269
- touches: ['docs/adr/', '.husky/'],
1270
- },
1271
-
1272
- {
1273
- ref: 'R62',
1274
- title: 'Memory + art-pipeline portability smoke tests',
1275
- description: `**Criterion:** C8.
1276
-
1277
- **Done when:**
1278
- - Two smoke scripts:
1279
- - \`scripts/gds/portability-smoke-memory.sh\` — fresh clone + Metic creds → /builder-setup → /builder-start → ship a tiny task → verify memory synced
1280
- - \`scripts/gds/portability-smoke-art.sh\` — fresh clone + own Gemini key → run \`art/pipeline/orchestrator.py\` on a single tile → succeeds
1281
- - Both wired into nightly CI on staging
1282
- - Failures file idea_inbox row for follow-up
1283
-
1284
- **Cross-refs:** Validates C8 end-to-end.`,
1285
- kind: 'spike',
1286
- discipline: 'engineering',
1287
- priority: 4,
1288
- est_minutes: 240,
1289
- manual_degree: 3,
1290
- credits_reward: 40,
1291
- touches: ['scripts/gds/', '.github/workflows/'],
1292
- },
1293
-
1294
- {
1295
- ref: 'R63',
1296
- title: 'Memory backup — server-side regular backups + restore drill',
1297
- description: `**Criterion:** C8.
1298
-
1299
- **Done when:**
1300
- - Nightly backup of builder_memory table to a Spaces bucket (or droplet local + offsite)
1301
- - 30-day retention; weekly archive
1302
- - Restore drill: pick a builder, restore their memory from yesterday's backup into a sandbox, verify content matches
1303
- - Documented in \`docs/recipes/memory-backup.md\`
1304
-
1305
- **Cross-refs:** Depends on R55. Cost: ~$1/month for Spaces if used.`,
1306
- kind: 'infra',
1307
- discipline: 'engineering',
1308
- priority: 4,
1309
- est_minutes: 180,
1310
- manual_degree: 3,
1311
- credits_reward: 30,
1312
- touches: ['scripts/gds/backup-memory.sh', 'docs/recipes/'],
1313
- },
1314
-
1315
- // =========================================================================
1316
- // TIER 5 — Red-team economy + advanced voice (P3).
1317
- // =========================================================================
1318
-
1319
- {
1320
- ref: 'R64',
1321
- title: 'vulnerability_reports table + schema',
1322
- description: `**Criterion:** C9.
1323
-
1324
- **Done when:**
1325
- - Migration: \`vulnerability_reports (id, reporter_builder_id, target text, severity text CHECK IN (low/med/high/critical), title, description, repro_steps_md, status text CHECK IN (open/repro_attempted/confirmed/disputed/fixed/wontfix), confirmed_at, fixed_at, fix_task_id, drachmae_awarded numeric, reported_at)\`
1326
- - Helper module \`src/bongos/security.js\`
1327
- - Per-builder read access (own reports + status); Archon reads all (via R67)
1328
-
1329
- **Cross-refs:** Foundation for R65, R67, R68.`,
1330
- kind: 'feature',
1331
- discipline: 'engineering',
1332
- priority: 3,
1333
- est_minutes: 120,
1334
- manual_degree: 2,
1335
- credits_reward: 20,
1336
- touches: ['migrations/', 'src/bongos/security.js', 'src/bongos/db.js'],
1337
- },
1338
-
1339
- {
1340
- ref: 'R65',
1341
- title: '/builder-redteam <severity> <title> skill — capture finding, draft security task, surface in Archon view',
1342
- description: `**Criterion:** C9.
1343
-
1344
- **Done when:**
1345
- - New skill at \`.claude/skills/builder-redteam/SKILL.md\` — Metic+ gated
1346
- - Walks the builder through: title, severity, target (route / file / endpoint), repro steps, expected vs actual
1347
- - POSTs to /api/gds/security/report; row inserted into vulnerability_reports
1348
- - Auto-drafts a security-kind task with kind='infra', parent='security-finding'
1349
- - Doesn't ping Archon directly; surfaces in R67's security view
1350
- - Returns a confirmation with the report id + "an automated subagent will attempt to reproduce within the hour"
1351
-
1352
- **Cross-refs:** Depends on R64. Pairs with R68 (auto-confirmation).`,
1353
- kind: 'feature',
1354
- discipline: 'engineering',
1355
- priority: 3,
1356
- est_minutes: 180,
1357
- manual_degree: 2,
1358
- credits_reward: 30,
1359
- touches: ['.claude/skills/builder-redteam/', 'src/bongos/routes/security.js'],
1360
- },
1361
-
1362
- {
1363
- ref: 'R66',
1364
- title: 'Drachmae payout table for vulnerability severity',
1365
- description: `**Criterion:** C9 — incentive structure.
1366
-
1367
- **Done when:**
1368
- - Config table or env var: low=10c, medium=50c, high=200c, critical=1000c (tunable; Archon can adjust via env)
1369
- - ADR documents the rationale
1370
- - Display visible on /builders hall under "Red-team rewards"
1371
-
1372
- **Cross-refs:** Used by R68 (auto-confirmation awards drachmae from this table).`,
1373
- kind: 'feature',
1374
- discipline: 'engineering',
1375
- priority: 3,
1376
- est_minutes: 60,
1377
- manual_degree: 1,
1378
- credits_reward: 10,
1379
- touches: ['src/bongos/security.js', 'docs/adr/', 'public-builders/'],
1380
- },
1381
-
1382
- {
1383
- ref: 'R67',
1384
- title: 'Archon-only security view in /builders dashboard',
1385
- description: `**Criterion:** C9.
1386
-
1387
- **Done when:**
1388
- - New tab/section in /builders hall (Archon-only) shows:
1389
- - Open vulnerability_reports with severity, reporter, repro
1390
- - audit_log filterable by builder/route/severity-of-route
1391
- - Dependency-scan alerts (R38)
1392
- - Recent auth-failure spikes (from R43 Grafana data)
1393
- - Each report has actions: confirm, dispute, mark fixed, link-to-fix-task
1394
-
1395
- **Cross-refs:** Depends on R64, R36, R38.`,
1396
- kind: 'feature',
1397
- discipline: 'engineering',
1398
- priority: 3,
1399
- est_minutes: 240,
1400
- manual_degree: 3,
1401
- credits_reward: 40,
1402
- touches: ['public-builders/', 'src/bongos/routes/security.js'],
1403
- },
1404
-
1405
- {
1406
- ref: 'R68',
1407
- title: 'Auto-confirmation flow — Opus subagent reproduces vuln on staging; awards drachmae automatically',
1408
- description: `**Criterion:** C9.
1409
-
1410
- **Why:** Replaces manual Archon confirmation. The grader pattern (already proven in R18-R22) applied to vulnerability reports.
1411
-
1412
- **Done when:**
1413
- - Scheduled task (every hour) picks up reports with status=open
1414
- - Spawns Opus subagent: "given these repro steps, attempt to reproduce on staging.amazonprimea.com. Report success/failure with evidence."
1415
- - On success: status → confirmed, drachmae auto-awarded (per R66), security task auto-created
1416
- - On failure: status → repro_attempted with subagent's reasoning; bounced back to reporter for clarification
1417
- - Archon can manually override either direction via R67
1418
-
1419
- **Cross-refs:** Depends on R40-R42, R64, R66, R67.`,
1420
- kind: 'feature',
1421
- discipline: 'engineering',
1422
- priority: 3,
1423
- est_minutes: 360,
1424
- manual_degree: 3,
1425
- credits_reward: 60,
1426
- touches: ['src/bongos/security.js', '.claude/scheduled-tasks/'],
1427
- },
1428
-
1429
- {
1430
- ref: 'R69',
1431
- title: 'Security ADR — server-side only, top-rank access only',
1432
- description: `**Criterion:** C9.
1433
-
1434
- **Why:** The threat model + mitigation details should not be in the public repo. Committed in heavily-redacted form (or only as a stub pointing to the server-side full version).
1435
-
1436
- **Done when:**
1437
- - Stub ADR in repo at \`docs/adr/0018-security-model-public-stub.md\` — public-safe overview, no specific defenses, no specific known weaknesses
1438
- - Full ADR lives in a server-side store (or a separate private repo) accessible only to Archon and Metic+ via a server endpoint
1439
- - The endpoint requires Metic+ (so Xenos doesn't see it)
1440
-
1441
- **Cross-refs:** Companion to R61 (secrets policy).`,
1442
- kind: 'feature',
1443
- discipline: 'engineering',
1444
- priority: 3,
1445
- est_minutes: 180,
1446
- manual_degree: 3,
1447
- credits_reward: 30,
1448
- touches: ['docs/adr/', 'src/bongos/routes/security.js'],
1449
- },
1450
-
1451
- {
1452
- ref: 'R70',
1453
- title: 'Weekly security review scheduled task',
1454
- description: `**Criterion:** C9.
1455
-
1456
- **Done when:**
1457
- - Scheduled task: every Sunday 09:00 ET, surfaces:
1458
- - Vulnerability reports older than 7 days still in open/repro_attempted state
1459
- - Security tasks older than 14 days
1460
- - Recent high-severity dep alerts
1461
- - Output posted as a single chat broadcast to Archon's private channel + a row in /builders security view
1462
- - Silent if nothing to surface
1463
-
1464
- **Cross-refs:** Depends on R64, R67.`,
1465
- kind: 'infra',
1466
- discipline: 'engineering',
1467
- priority: 3,
1468
- est_minutes: 120,
1469
- manual_degree: 2,
1470
- credits_reward: 20,
1471
- touches: ['.claude/scheduled-tasks/'],
1472
- },
1473
-
1474
- {
1475
- ref: 'R71',
1476
- title: 'Nightly skill-usage feedback loop scheduled task (Metic+ visibility only)',
1477
- description: `**Criterion:** C5 — builders steer system evolution.
1478
-
1479
- **Done when:**
1480
- - Scheduled task at \`.claude/scheduled-tasks/skill-usage-review/\` aggregates last 24h of skill invocations
1481
- - Identifies friction patterns: same skill invoked > N times in a session, skill exit codes non-zero, builder visibly retried steps
1482
- - Files idea_inbox rows (kind='skill-friction') summarizing the pattern
1483
- - Metic+ only — Xenos don't see skill-friction ideas in their inbox view
1484
-
1485
- **Cross-refs:** Promotes idea_inbox #22.`,
1486
- kind: 'feature',
1487
- discipline: 'engineering',
1488
- priority: 3,
1489
- est_minutes: 240,
1490
- manual_degree: 3,
1491
- credits_reward: 40,
1492
- touches: ['.claude/scheduled-tasks/', 'src/bongos/inbox.js'],
1493
- promoted_idea_id: 22,
1494
- },
1495
-
1496
- {
1497
- ref: 'R72',
1498
- title: 'Priority sessions skill — plain-speech questions weight idea_inbox',
1499
- description: `**Criterion:** C5.
1500
-
1501
- **Why:** Planning sessions set criteria; priority sessions weight what's in flight right now. The trusted builder answers a small set of plain-speech questions ("what feels stuck?", "what would unblock the most builders?", "what excites you?"), and the answers reweight idea_inbox priorities + suggest task promotions.
1502
-
1503
- **Done when:**
1504
- - Skill at \`.claude/skills/priority-session/SKILL.md\` — Metic+ gated
1505
- - Conversation walks 5-7 plain questions
1506
- - Output: weighted ranking of open ideas + a "what should I claim next?" suggestion
1507
- - Writes a session-log entry
1508
-
1509
- **Cross-refs:** Promotes idea_inbox #18.`,
1510
- kind: 'feature',
1511
- discipline: 'engineering',
1512
- priority: 3,
1513
- est_minutes: 240,
1514
- manual_degree: 3,
1515
- credits_reward: 40,
1516
- touches: ['.claude/skills/priority-session/'],
1517
- promoted_idea_id: 18,
1518
- },
1519
-
1520
- {
1521
- ref: 'R73',
1522
- title: 'Builder analytics — historical "AI dev curve" per builder',
1523
- description: `**Criterion:** C5.
1524
-
1525
- **Done when:**
1526
- - /builders profile page gets an analytics panel: ship rate over time, cost-per-task trend, confirmation rate, average task duration trend, top kinds shipped
1527
- - Sparkline charts (no heavy chart library — Chart.js if needed)
1528
- - Archon's view aggregates across all builders
1529
- - Public-facing summary on /status hides individuals but shows ecosystem trends
1530
-
1531
- **Cross-refs:** Promotes idea_inbox #35.`,
1532
- kind: 'feature',
1533
- discipline: 'engineering',
1534
- priority: 3,
1535
- est_minutes: 360,
1536
- manual_degree: 3,
1537
- credits_reward: 60,
1538
- touches: ['public-builders/', 'src/bongos/routes/analytics.js'],
1539
- promoted_idea_id: 35,
1540
- },
1541
-
1542
- {
1543
- ref: 'R74',
1544
- title: 'Calibration dashboard (Archon view) — grader signal per builder × kind × time',
1545
- description: `**Criterion:** C4.
1546
-
1547
- **Done when:**
1548
- - Archon-only page (or Grafana panel) shows grader scores over time, broken down by builder + task kind
1549
- - Trends visible: is Builder X drifting? Is the bar tightening?
1550
- - Alerts on anomalies (single builder's confirmation rate falls > 30% week-over-week)
1551
-
1552
- **Cross-refs:** Depends on R20, R22, R43.`,
1553
- kind: 'feature',
1554
- discipline: 'engineering',
1555
- priority: 3,
1556
- est_minutes: 180,
1557
- manual_degree: 3,
1558
- credits_reward: 30,
1559
- touches: ['public-builders/', 'infra/grafana/dashboards/'],
1560
- },
1561
-
1562
- {
1563
- ref: 'R75',
1564
- title: 'Manual-override request flow (rare path)',
1565
- description: `**Criterion:** C4.
1566
-
1567
- **Done when:**
1568
- - If the grader rejects and the builder thinks the grader is wrong, they can POST /api/gds/tasks/:id/override-request with a rationale
1569
- - Surfaces in Archon's queue (R67)
1570
- - Archon decides yes/no; on yes, task flips to confirmed manually
1571
- - Audit-logged
1572
-
1573
- **Cross-refs:** Depends on R67. Should be rare — < 5% of ships.`,
1574
- kind: 'feature',
1575
- discipline: 'engineering',
1576
- priority: 3,
1577
- est_minutes: 90,
1578
- manual_degree: 2,
1579
- credits_reward: 15,
1580
- touches: ['src/bongos/routes/tasks.js', 'public-builders/'],
1581
- },
1582
-
1583
- // =========================================================================
1584
- // TIER 6 — Onboarding polish + remaining (P2).
1585
- // =========================================================================
1586
-
1587
- {
1588
- ref: 'R76',
1589
- title: 'Auto-completing onboarding checklist — state machine fires on builder events',
1590
- description: `**Criterion:** C1.
1591
-
1592
- **Why:** New builders shouldn't have to track where they are in onboarding. A state machine on the server fires events as they go (Device Flow complete, first /builder-start, first claim, first ship, first karma vote received) and ticks off a checklist visible in /builders hall.
1593
-
1594
- **Done when:**
1595
- - Migration: \`builder_onboarding_state (builder_id PK, current_stage text, completed_stages text[], started_at, completed_at)\`
1596
- - Stages: \`auth_complete\`, \`primer_read\`, \`first_start\`, \`first_claim\`, \`first_ship\`, \`first_vote_received\`, \`graduated\`
1597
- - Server-side hooks fire on each event
1598
- - /builders hall renders the checklist for the current builder (read-only for others)
1599
- - On completion: chat broadcast "<name> has completed onboarding"
1600
-
1601
- **Cross-refs:** Depends on R04, R13. Pairs with R77 (diagrams).`,
1602
- kind: 'feature',
1603
- discipline: 'engineering',
1604
- priority: 2,
1605
- est_minutes: 300,
1606
- manual_degree: 2,
1607
- credits_reward: 50,
1608
- touches: ['migrations/', 'src/bongos/onboarding.js', 'public-builders/'],
1609
- },
1610
-
1611
- {
1612
- ref: 'R77',
1613
- title: 'Visual diagrams of how GDS works — Mermaid + PNG flowcharts',
1614
- description: `**Criterion:** C1.
1615
-
1616
- **Done when:**
1617
- - 5 diagrams in \`docs/onboarding/diagrams/\`:
1618
- 1. Claim → ship lifecycle (states + transitions)
1619
- 2. Rank ladder (Xenos / Metic / Archon + permissions)
1620
- 3. Drachmae / karma sourcing (where each comes from, where each is spent)
1621
- 4. Server ↔ repo ↔ memory layered model
1622
- 5. Two-track versioning (product / internal) and how planning sessions feed it
1623
- - Mermaid source committed; PNGs rendered for embed in primer doc
1624
- - Linked from R12 (primer)
1625
-
1626
- **Cross-refs:** Pairs with R12.`,
1627
- kind: 'feature',
1628
- discipline: 'creative',
1629
- priority: 2,
1630
- est_minutes: 240,
1631
- manual_degree: 3,
1632
- credits_reward: 40,
1633
- touches: ['docs/onboarding/diagrams/'],
1634
- },
1635
-
1636
- {
1637
- ref: 'R78',
1638
- title: '/builders hall first-visit welcome panel',
1639
- description: `**Criterion:** C1.
1640
-
1641
- **Done when:**
1642
- - On first /builders visit by a new builder, render a welcome panel: their rank, what's unlocked, next checklist step (from R76), link to primer (R12), link to /builder-start
1643
- - Dismissable; reappears if onboarding_state stage regresses (rare)
1644
-
1645
- **Cross-refs:** Depends on R13, R76.`,
1646
- kind: 'feature',
1647
- discipline: 'engineering',
1648
- priority: 2,
1649
- est_minutes: 90,
1650
- manual_degree: 2,
1651
- credits_reward: 15,
1652
- touches: ['public-builders/'],
1653
- },
1654
-
1655
- {
1656
- ref: 'R79',
1657
- title: 'Auto-generator for low-drachmae newcomer tasks — from code-review findings + design prompts',
1658
- description: `**Criterion:** C1 — newcomer queue always populated.
1659
-
1660
- **Why:** R14 added the newcomer_friendly flag; this task ensures there's always supply. Two sources:
1661
- - Engineering newcomers: overnight code-review findings tagged low-severity and well-scoped get auto-promoted into tasks tagged newcomer_friendly with low drachmae rewards
1662
- - Creative newcomers: a small prompt library generates "design a new NPC sketch" / "write a vendor flavor line" / "name a building" tasks
1663
-
1664
- **Done when:**
1665
- - Scheduled task: if open newcomer_friendly task count < 3, generate one from each pool
1666
- - Engineering pool sources from \`.claude/scheduled-tasks/overnight-code-review/\` findings
1667
- - Creative pool draws from a curated prompt list in \`art/template/newcomer-prompts.json\`
1668
- - Auto-generated tasks tagged \`source='auto-newcomer-generator'\`
1669
-
1670
- **Cross-refs:** Depends on R14. Cross-link to R81 (discipline gating).`,
1671
- kind: 'feature',
1672
- discipline: 'engineering',
1673
- priority: 2,
1674
- est_minutes: 240,
1675
- manual_degree: 3,
1676
- credits_reward: 40,
1677
- touches: ['.claude/scheduled-tasks/newcomer-generator/', 'art/template/'],
1678
- },
1679
-
1680
- {
1681
- ref: 'R80',
1682
- title: 'Onboarding session logs auto-publish to server + passive analysis pipeline',
1683
- description: `**Criterion:** C1 — feedback without asking.
1684
-
1685
- **Why:** Instead of asking new builders "what was confusing?" we read their actual session logs and analyze patterns. Logs auto-publish during onboarding (with explicit consent at /builder-setup); a passive analysis pipeline extracts friction.
1686
-
1687
- **Done when:**
1688
- - /builder-setup asks: "May we read your onboarding session logs to improve the system? [Y/n]"
1689
- - On consent: a SessionStart/SessionEnd hook ships the session transcript (compressed) to server during the onboarding window
1690
- - Passive analysis (Opus subagent) reads each transcript, flags moments of confusion (long Claude responses that didn't resolve, repeated similar prompts, error recovery attempts)
1691
- - Files idea_inbox row per flagged session (kind='onboarding-friction')
1692
-
1693
- **Cross-refs:** Pairs with R71.`,
1694
- kind: 'feature',
1695
- discipline: 'engineering',
1696
- priority: 2,
1697
- est_minutes: 360,
1698
- manual_degree: 3,
1699
- credits_reward: 60,
1700
- touches: ['scripts/gds/', '.claude/hooks/', 'src/bongos/onboarding.js'],
1701
- },
1702
-
1703
- {
1704
- ref: 'R81',
1705
- title: 'Discipline-gated builder experience + cross-discipline recommendations',
1706
- description: `**Criterion:** C1, C5.
1707
-
1708
- **Why:** A creative builder shouldn't be shown only engineering tasks at /builder-start. Routing by discipline gives a better experience; cross-discipline recommendations expose options.
1709
-
1710
- **Done when:**
1711
- - /builder-start filters claimable_tasks by builder.preferred_disciplines (R82) by default
1712
- - A "show all disciplines" toggle exists
1713
- - A "you might enjoy" section shows 2-3 tasks outside the builder's discipline, ranked by relevance
1714
-
1715
- **Cross-refs:** Promotes idea_inbox #36. Depends on R82.`,
1716
- kind: 'feature',
1717
- discipline: 'engineering',
1718
- priority: 2,
1719
- est_minutes: 180,
1720
- manual_degree: 2,
1721
- credits_reward: 30,
1722
- touches: ['scripts/gds/start.js', 'src/bongos/db.js'],
1723
- promoted_idea_id: 36,
1724
- },
1725
-
1726
- {
1727
- ref: 'R82',
1728
- title: 'builders.preferred_disciplines text[] column',
1729
- description: `**Criterion:** C1.
1730
-
1731
- **Done when:**
1732
- - Migration adds the column (default \`{}\`)
1733
- - /builder-setup asks the new builder which disciplines they're interested in (creative, engineering, both)
1734
- - /builders profile lets them edit later
1735
- - Validated against tasks.discipline enum
1736
-
1737
- **Cross-refs:** Pairs with R81.`,
1738
- kind: 'feature',
1739
- discipline: 'engineering',
1740
- priority: 2,
1741
- est_minutes: 60,
1742
- manual_degree: 2,
1743
- credits_reward: 10,
1744
- touches: ['migrations/', 'scripts/gds/setup.js', 'public-builders/'],
1745
- },
1746
-
1747
- {
1748
- ref: 'R83',
1749
- title: 'Task-level requires_rank column',
1750
- description: `**Criterion:** C2.
1751
-
1752
- **Why:** R14 added newcomer_friendly (Xenos-claimable). The inverse: some tasks are Metic-only because they touch sensitive infra. Add an explicit \`requires_rank\` column.
1753
-
1754
- **Done when:**
1755
- - Migration: \`tasks.requires_rank text DEFAULT 'Xenos'\` (Xenos = anyone; Metic = trusted only; Archon = me)
1756
- - claimable_tasks view filters by current builder rank
1757
- - Server-side enforcement on POST /claims
1758
-
1759
- **Cross-refs:** Depends on R04, R14. Sub-case of the rank-gating pattern.`,
1760
- kind: 'feature',
1761
- discipline: 'engineering',
1762
- priority: 2,
1763
- est_minutes: 90,
1764
- manual_degree: 2,
1765
- credits_reward: 15,
1766
- touches: ['migrations/', 'src/bongos/db.js', 'src/bongos/routes/claims.js'],
1767
- },
1768
-
1769
- {
1770
- ref: 'R84',
1771
- title: '/api/gds/me MTD spend + soft-cap 80% warning + hard-cap 100% refusal',
1772
- description: `**Criterion:** C3.
1773
-
1774
- **Done when:**
1775
- - /api/gds/me returns: \`{ spend_mtd_usd, budget_mtd_usd, pct_used }\`
1776
- - At 80%: chat ping to that builder + visible warning on /builders profile
1777
- - At 100%: write paths that incur cost (ship, art-pipeline runs) refuse with structured error
1778
- - Budget per-builder configurable by Archon
1779
-
1780
- **Cross-refs:** Depends on R85.`,
1781
- kind: 'feature',
1782
- discipline: 'engineering',
1783
- priority: 2,
1784
- est_minutes: 180,
1785
- manual_degree: 2,
1786
- credits_reward: 30,
1787
- touches: ['src/bongos/routes/me.js', 'src/bongos/cost.js', 'public-builders/'],
1788
- },
1789
-
1790
- {
1791
- ref: 'R85',
1792
- title: 'cost_log.builder_id attribution audit + /status spend transparency',
1793
- description: `**Criterion:** C3.
1794
-
1795
- **Done when:**
1796
- - Audit every code path that writes to cost_log; verify builder_id is populated correctly (never NULL, never lars-as-proxy)
1797
- - Backfill any historical rows that need correction
1798
- - /status page gains a "per-builder spend" row (anonymized or named, your call) so the community sees system cost honestly
1799
-
1800
- **Cross-refs:** Depends on R11. Foundation for R84.`,
1801
- kind: 'cleanup',
1802
- discipline: 'engineering',
1803
- priority: 2,
1804
- est_minutes: 120,
1805
- manual_degree: 2,
1806
- credits_reward: 20,
1807
- touches: ['src/bongos/cost.js', 'scripts/gds/backfill-cost.js', 'public-status/'],
1808
- },
1809
-
1810
- {
1811
- ref: 'R86',
1812
- title: 'Skill efficiency pass + builder-toggleable per-skill model selector on /builders page',
1813
- description: `**Criterion:** cross-cutting — cost discipline.
1814
-
1815
- **Why:** Every slash command burns LLM credits on mechanism (parsing JSON, checking rank, formatting output) and judgment (deciding what to claim, writing a task description). The mechanism work should run on cheap models or no LLM (direct script); judgment stays on Opus. Plus: builders should be able to pick their model preferences per skill.
1816
-
1817
- **Done when:**
1818
- - Audit every \`.claude/skills/*/SKILL.md\` — categorize each step as mechanism or judgment
1819
- - Refactor mechanism into pure scripts (no LLM)
1820
- - Skill files updated to delegate accordingly
1821
- - /builders profile gains a model-selector matrix: skill-kind × model (Opus, Sonnet, Haiku) — defaults to Opus for judgment, scripts for mechanism
1822
- - Per-builder preferences read at skill-execution time
1823
- - Cost-per-skill-invocation measured before + after, documented in ADR
1824
-
1825
- **Cross-refs:** Promotes idea_inbox #21. Pulls forward a minimal slice of GDS-V4 idea #30.`,
1826
- kind: 'feature',
1827
- discipline: 'engineering',
1828
- priority: 2,
1829
- est_minutes: 480,
1830
- manual_degree: 3,
1831
- credits_reward: 80,
1832
- touches: ['.claude/skills/', 'scripts/gds/', 'src/bongos/db.js', 'public-builders/', 'docs/adr/'],
1833
- promoted_idea_id: 21,
1834
- },
1835
-
1836
- // =========================================================================
1837
- // TIER 7 — End-of-V3 lockdown (P1).
1838
- // =========================================================================
1839
-
1840
- {
1841
- ref: 'R87',
1842
- title: 'CLAUDE.md audit — categorize each claim as descriptive vs canonical; relocate canonical items to DB',
1843
- description: `**Criterion:** C7.
1844
-
1845
- **Why:** CLAUDE.md is the index for AI agents but also contains de facto state ("here's our rank ladder", "here's the trust boundary"). Some of that is canonical and should live server-side (DB or server-only doc); some is descriptive and stays in the file. Audit + relocate.
1846
-
1847
- **Done when:**
1848
- - Each section of CLAUDE.md tagged (in a temporary review doc) as descriptive or canonical
1849
- - Canonical sections relocated server-side (e.g., rank ladder definitions to a \`docs/canonical-permissions.md\` that's read-only, or to the DB)
1850
- - CLAUDE.md gains a top-of-file disclaimer: "This file is descriptive. The source of truth for permissions, scope, and state is the GDS database accessed via /api/gds/*."
1851
- - Long-form sections that grew too big get split into smaller files
1852
-
1853
- **Cross-refs:** Heaviest at end of V3 so it reflects all V3 changes. Depends on R02 (trust-boundary ADR).`,
1854
- kind: 'cleanup',
1855
- discipline: 'engineering',
1856
- priority: 1,
1857
- est_minutes: 360,
1858
- manual_degree: 3,
1859
- credits_reward: 60,
1860
- touches: ['CLAUDE.md', 'docs/'],
1861
- },
1862
-
1863
- {
1864
- ref: 'R88',
1865
- title: 'Rank-gate /planning-session skill to Metic+ (end-of-V3 lockdown)',
1866
- description: `**Criterion:** C2, C7 — your explicit end-of-V3 ask.
1867
-
1868
- **Why:** The planning-session skill is shipped by V3.R00 with no rank gate so V3 itself can use it. Once V3 ships, only Metics + Archon should be able to open planning sessions.
1869
-
1870
- **Done when:**
1871
- - \`.claude/skills/planning-session/SKILL.md\` opening check enforces Metic+
1872
- - Server-side: any endpoint the skill calls enforces requireRank('Metic')
1873
- - Smoke: Xenos opens /planning-session → "this skill requires Metic+; ask Archon for promotion"
1874
- - Documented as part of V3's "lockdown" tasks
1875
-
1876
- **Cross-refs:** Depends on R05, R30 (same rank-gate pattern as idea-triage).`,
1877
- kind: 'feature',
1878
- discipline: 'engineering',
1879
- priority: 1,
1880
- est_minutes: 60,
1881
- manual_degree: 2,
1882
- credits_reward: 10,
1883
- touches: ['.claude/skills/planning-session/', 'src/bongos/routes/inbox.js', 'src/bongos/routes/done-when.js'],
1884
- },
1885
-
1886
- {
1887
- ref: 'R89',
1888
- title: 'Graceful builder exit — transfer claims, archive memory, preserve credit/karma history',
1889
- description: `**Criterion:** robustness — what happens when a builder quits.
1890
-
1891
- **Done when:**
1892
- - New skill or endpoint: \`/builder-exit\` or PATCH /builders/:id/status='inactive' (Archon-only, or self-service with Archon approval)
1893
- - On exit: active claims released cleanly; outstanding session_logs sealed; memory archived to a long-term store (not deleted); rank → Xenos; can't claim new tasks
1894
- - Drachmae + karma history preserved indefinitely
1895
- - Builder can be re-activated by Archon if they return
1896
-
1897
- **Cross-refs:** Should be available before exits actually happen — file but don't necessarily ship until needed. Could be deprioritized further.`,
1898
- kind: 'feature',
1899
- discipline: 'engineering',
1900
- priority: 1,
1901
- est_minutes: 240,
1902
- manual_degree: 3,
1903
- credits_reward: 40,
1904
- touches: ['src/bongos/routes/builders.js', '.claude/skills/'],
1905
- },
1906
- ];
1907
-
1908
- // ---------------------------------------------------------------------------
1909
- // Main: post each task; PATCH idea_inbox for promotions
1910
- // ---------------------------------------------------------------------------
1911
-
1912
- async function main() {
1913
- await requireSession();
1914
- const api = await cliClient();
1915
-
1916
- // Pull current GDS-V3 tasks for idempotency by source_ref
1917
- const list = await api.tasks.getTasks({ query: { version: 'GDS-V3' } });
1918
- const bySourceRef = {};
1919
- for (const t of list.data?.tasks || []) {
1920
- if (t.source_ref) bySourceRef[t.source_ref] = t;
1921
- }
1922
-
1923
- let created = 0, skipped = 0, errors = 0, promoted = 0;
1924
- for (const def of TASKS) {
1925
- const source_ref = `gds-v3-${def.ref.toLowerCase()}`;
1926
- if (bySourceRef[source_ref]) {
1927
- console.log(`SKIP ${def.ref} (already exists: id=${bySourceRef[source_ref].id})`);
1928
- skipped++;
1929
- continue;
1930
- }
1931
- const body = {
1932
- version_id: 'GDS-V3',
1933
- title: `V3.${def.ref} — ${def.title}`,
1934
- description: def.description,
1935
- kind: def.kind,
1936
- discipline: def.discipline,
1937
- status: 'backlog',
1938
- priority: def.priority,
1939
- est_minutes: def.est_minutes,
1940
- manual_degree: def.manual_degree,
1941
- credits_reward: def.credits_reward,
1942
- touches: def.touches || [],
1943
- source: 'planning-session',
1944
- source_ref,
1945
- };
1946
- if (DRY) {
1947
- console.log(`DRY ${def.ref} P${def.priority} ${def.kind} ${def.est_minutes}m ${def.credits_reward}c ${def.title.slice(0, 60)}`);
1948
- continue;
1949
- }
1950
- const res = await api.tasks.postTasks({ body });
1951
- if (res.status !== 201) {
1952
- console.error(`FAIL ${def.ref}: status=${res.status} ${JSON.stringify(res.data).slice(0, 200)}`);
1953
- errors++;
1954
- continue;
1955
- }
1956
- const newId = res.data.task.id;
1957
- console.log(`OK ${def.ref} → task id=${newId}`);
1958
- created++;
1959
-
1960
- if (def.promoted_idea_id) {
1961
- const patch = await api.inbox.patchInboxId({ id: def.promoted_idea_id, body: {
1962
- status: 'promoted',
1963
- promoted_to_task_id: Number(newId),
1964
- } });
1965
- if (patch.status === 200) {
1966
- console.log(` promoted idea_inbox #${def.promoted_idea_id} → task ${newId}`);
1967
- promoted++;
1968
- } else {
1969
- console.error(` FAIL promote idea #${def.promoted_idea_id}: ${patch.status} ${JSON.stringify(patch.data).slice(0, 200)}`);
1970
- }
1971
- }
1972
- }
1973
-
1974
- console.log(`\nDONE created=${created} skipped=${skipped} errors=${errors} ideas_promoted=${promoted} (total in manifest: ${TASKS.length})`);
1975
- process.exit(errors === 0 ? 0 : 1);
1976
- }
1977
-
1978
- main().catch((err) => {
1979
- console.error('FATAL', err);
1980
- process.exit(1);
1981
- });