Every action becomes a queued task assigned to a crew team (lead + optional helpers). Nothing resolves instantly; time advances only via POST /api/turn.
duration model (§4; power 1 for everyone until #45)
trait duration modifiers (§5)
UI: NEXT TURN button bottom-right + turn counter, crew picker with live duration, task strip
OpenAPI update
rework existing unit/e2e assertions from instant-resolution to the queue+tick model
Acceptance criteria
tasks table per spec §3 (id, saveId, type JUMP|EXPLORE|SHIP_UPGRADE|SHIP_EXPAND|SHIP_BUILD|RESEARCH, payload JSON, leadCrewId, helpers JSON array, duration, remaining, status ACTIVE|PENDING|DONE); DDL in lib/db/client.ts synced with lib/db/schema.ts; idempotent backfill for existing saves
POST /api/turn advances exactly 1 turn: decrement ACTIVE tasks → resolve completions (per-type resolvers reusing save.ts / ship / research logic) → grant events → free team → auto-start FIFO successors → mission-completion checks; returns full snapshot
All action endpoints queue instead of resolving (POST /api/jump, /api/explore, /api/ship/{upgrade,expand,build}, /api/research gain leadCrewId + helperCrewIds[]); no turn increment on queue; costs deducted at queue time (ship work & research)
Duration = max(1, ceil(work / totalPower) + mismatchPenalty + traitModifierSum); work points EXPLORE 4 · JUMP hops×3 · SHIP 6 · RESEARCH 9; power 1 per crew until #45; all constants in new lib/game/crew-costs.ts (§11)
Role mismatch: lead outside preferred role → +1 turn (JUMP→PILOT/NAVIGATOR · EXPLORE→SCIENTIST · SHIP work→ENGINEER/TECHNICIAN · RESEARCH→SCIENTIST); helpers never penalised; STEADY UNDER PRESSURE cancels it
Trait duration modifiers per §5 tables apply to the lead only (7 good + 8 bad)
In-transit rule per §3: no new queuing while a JUMP is ACTIVE; pending jumps do not block; only one JUMP at a time (active or pending); non-jump work continues through the jump and resolves against its target
Mission accept becomes instant/free; completion checks run on tick when the satisfying task completes (jump arrival → DELIVER; scan → EXPLORE/FIND)
Snapshots (world/system/crew responses) gain active+pending tasks array {id, type, targetLabel, leadName, helperNames[], remaining}; admin CRUD panel picks up new tables automatically
UI: NEXT TURN button fixed bottom-right + turn counter (empty queue = free skip); inline team builder (lead radio + helper checkboxes) with live-computed duration; busy/committed members disabled with reason; active-tasks strip bottom-left, pending FIFO tasks dimmed
OpenAPI spec updated in lib/openapi.ts
Unit tests per §9: duration matrix (work values × power bands × mismatch × traits), queue validation rules (busy 409, in-transit 409, second jump 409), tick resolution (completion effects, FIFO auto-start, mission checks), cost deduction at queue time
E2E reworked to the queue+tick model per §9 (CI-only)
Process (AGENTS.md loop)
One feature branch off master → version bump v0.10.0 + CHANGELOG entry at top → local verify (npx tsc --noEmit, npx vitest run, npx playwright test --list; no local e2e) → push, CI auto-merge on green (verify merged_at) → tag v0.10.0 on master → manual deploy (docker compose up -d --build) → close issue with comment.
Also: flip the spec doc status line to approved and correct its §10 table issue numbers (#44 engine, #45 skills, #43 traits) when committing it on this branch.
**Spec:** `docs/superpowers/specs/2026-10-01-crew-driven-actions-design.md` — §3, §4, §5 (duration modifiers), §7, §8, §9, §11
Every action becomes a queued task assigned to a crew team (lead + optional helpers). Nothing resolves instantly; time advances only via `POST /api/turn`.
## Scope
- tasks table (schema v7; backfill creates empty table for existing saves)
- POST /api/turn tick
- all action endpoints → queueing with lead+helpers
- duration model (§4; power 1 for everyone until #45)
- trait duration modifiers (§5)
- UI: NEXT TURN button bottom-right + turn counter, crew picker with live duration, task strip
- OpenAPI update
- rework existing unit/e2e assertions from instant-resolution to the queue+tick model
## Acceptance criteria
- [ ] `tasks` table per spec §3 (id, saveId, type JUMP|EXPLORE|SHIP_UPGRADE|SHIP_EXPAND|SHIP_BUILD|RESEARCH, payload JSON, leadCrewId, helpers JSON array, duration, remaining, status ACTIVE|PENDING|DONE); DDL in lib/db/client.ts synced with lib/db/schema.ts; idempotent backfill for existing saves
- [ ] `POST /api/turn` advances exactly 1 turn: decrement ACTIVE tasks → resolve completions (per-type resolvers reusing save.ts / ship / research logic) → grant events → free team → auto-start FIFO successors → mission-completion checks; returns full snapshot
- [ ] All action endpoints queue instead of resolving (`POST /api/jump`, `/api/explore`, `/api/ship/{upgrade,expand,build}`, `/api/research` gain `leadCrewId` + `helperCrewIds[]`); no turn increment on queue; costs deducted at queue time (ship work & research)
- [ ] Duration = max(1, ceil(work / totalPower) + mismatchPenalty + traitModifierSum); work points EXPLORE 4 · JUMP hops×3 · SHIP 6 · RESEARCH 9; power 1 per crew until #45; all constants in new lib/game/crew-costs.ts (§11)
- [ ] Role mismatch: lead outside preferred role → +1 turn (JUMP→PILOT/NAVIGATOR · EXPLORE→SCIENTIST · SHIP work→ENGINEER/TECHNICIAN · RESEARCH→SCIENTIST); helpers never penalised; STEADY UNDER PRESSURE cancels it
- [ ] Trait duration modifiers per §5 tables apply to the lead only (7 good + 8 bad)
- [ ] Validation: unknown crew → 404; busy/committed crew → 409; in-transit or second jump → 409; unreachable target / unaffordable cost / build gate → existing error codes
- [ ] In-transit rule per §3: no new queuing while a JUMP is ACTIVE; pending jumps do not block; only one JUMP at a time (active or pending); non-jump work continues through the jump and resolves against its target
- [ ] Mission accept becomes instant/free; completion checks run on tick when the satisfying task completes (jump arrival → DELIVER; scan → EXPLORE/FIND)
- [ ] Snapshots (world/system/crew responses) gain active+pending tasks array {id, type, targetLabel, leadName, helperNames[], remaining}; admin CRUD panel picks up new tables automatically
- [ ] UI: NEXT TURN button fixed bottom-right + turn counter (empty queue = free skip); inline team builder (lead radio + helper checkboxes) with live-computed duration; busy/committed members disabled with reason; active-tasks strip bottom-left, pending FIFO tasks dimmed
- [ ] OpenAPI spec updated in lib/openapi.ts
- [ ] Unit tests per §9: duration matrix (work values × power bands × mismatch × traits), queue validation rules (busy 409, in-transit 409, second jump 409), tick resolution (completion effects, FIFO auto-start, mission checks), cost deduction at queue time
- [ ] E2E reworked to the queue+tick model per §9 (CI-only)
## Process (AGENTS.md loop)
One feature branch off master → version bump v0.10.0 + CHANGELOG entry at top → local verify (`npx tsc --noEmit`, `npx vitest run`, `npx playwright test --list`; no local e2e) → push, CI auto-merge on green (verify merged_at) → tag v0.10.0 on master → manual deploy (`docker compose up -d --build`) → close issue with comment.
Also: flip the spec doc status line to approved and correct its §10 table issue numbers (#44 engine, #45 skills, #43 traits) when committing it on this branch.
v0.10.1 merged to master — PR #47, merge commit 678cd48a.
Shipped:
Hydration-safe banner clock (f1633eb) — the React 19 hydration mismatch on every production load (the build-time clock in the prerendered banner) is fixed; CI-verified (no hydration errors in any job log).
World-map jump dispatch fix (e792c8a) — the ACTUAL cause of the three deterministically red e2e jump specs: TeamBuilder's blocked term was undefined (not null) whenever no jump was queued (Array.find semantics), so the roster rendered (truthiness check) while the DISPATCH button's blocked !== null guard read it as blocked — the JUMP panel's dispatch was permanently dead on an empty queue, i.e. in the state every one of those specs reaches (smoke 174/202/516, red on runs 396/399/400 with 300 s waitForResponse timeouts). The fix coalesces the queued-jump search to null so blocked is strictly QueueDto | null.
Verification: full e2e suite green on the merged head (run 402 / job 413: 26/26, including the three formerly red specs, 5.7–6.9 s each; restart-persistence spec green); unit suite green (166 tests).
Deploy: PENDING — the deploy guard requires a clean main checkout, but /home/krzyw/projects/sandbox/space-wanderer has untracked .opencode/ and docs/, so the first production deploy was skipped; https://space-wanderer.dev.kkhost.pl is still undeployed (404). To ship: reset the main checkout to origin/master (keeping the untracked files) and run docker compose up -d --build there, then verify /api/version = 0.10.1.
v0.10.1 merged to master — PR #47, merge commit 678cd48a.
Shipped:
- Hydration-safe banner clock (f1633eb) — the React 19 hydration mismatch on every production load (the build-time clock in the prerendered banner) is fixed; CI-verified (no hydration errors in any job log).
- World-map jump dispatch fix (e792c8a) — the ACTUAL cause of the three deterministically red e2e jump specs: TeamBuilder's `blocked` term was `undefined` (not `null`) whenever no jump was queued (`Array.find` semantics), so the roster rendered (truthiness check) while the DISPATCH button's `blocked !== null` guard read it as blocked — the JUMP panel's dispatch was permanently dead on an empty queue, i.e. in the state every one of those specs reaches (smoke 174/202/516, red on runs 396/399/400 with 300 s `waitForResponse` timeouts). The fix coalesces the queued-jump search to null so `blocked` is strictly `QueueDto | null`.
Verification: full e2e suite green on the merged head (run 402 / job 413: 26/26, including the three formerly red specs, 5.7–6.9 s each; restart-persistence spec green); unit suite green (166 tests).
Tags: v0.10.0 → 9020a77, v0.10.1 → 678cd48a.
Deploy: PENDING — the deploy guard requires a clean main checkout, but `/home/krzyw/projects/sandbox/space-wanderer` has untracked `.opencode/` and `docs/`, so the first production deploy was skipped; https://space-wanderer.dev.kkhost.pl is still undeployed (404). To ship: reset the main checkout to origin/master (keeping the untracked files) and run `docker compose up -d --build` there, then verify `/api/version` = 0.10.1.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Spec:
docs/superpowers/specs/2026-10-01-crew-driven-actions-design.md— §3, §4, §5 (duration modifiers), §7, §8, §9, §11Every action becomes a queued task assigned to a crew team (lead + optional helpers). Nothing resolves instantly; time advances only via
POST /api/turn.Scope
Acceptance criteria
taskstable per spec §3 (id, saveId, type JUMP|EXPLORE|SHIP_UPGRADE|SHIP_EXPAND|SHIP_BUILD|RESEARCH, payload JSON, leadCrewId, helpers JSON array, duration, remaining, status ACTIVE|PENDING|DONE); DDL in lib/db/client.ts synced with lib/db/schema.ts; idempotent backfill for existing savesPOST /api/turnadvances exactly 1 turn: decrement ACTIVE tasks → resolve completions (per-type resolvers reusing save.ts / ship / research logic) → grant events → free team → auto-start FIFO successors → mission-completion checks; returns full snapshotPOST /api/jump,/api/explore,/api/ship/{upgrade,expand,build},/api/researchgainleadCrewId+helperCrewIds[]); no turn increment on queue; costs deducted at queue time (ship work & research)Process (AGENTS.md loop)
One feature branch off master → version bump v0.10.0 + CHANGELOG entry at top → local verify (
npx tsc --noEmit,npx vitest run,npx playwright test --list; no local e2e) → push, CI auto-merge on green (verify merged_at) → tag v0.10.0 on master → manual deploy (docker compose up -d --build) → close issue with comment.Also: flip the spec doc status line to approved and correct its §10 table issue numbers (#44 engine, #45 skills, #43 traits) when committing it on this branch.
v0.10.1 merged to master — PR #47, merge commit
678cd48a.Shipped:
f1633eb) — the React 19 hydration mismatch on every production load (the build-time clock in the prerendered banner) is fixed; CI-verified (no hydration errors in any job log).e792c8a) — the ACTUAL cause of the three deterministically red e2e jump specs: TeamBuilder'sblockedterm wasundefined(notnull) whenever no jump was queued (Array.findsemantics), so the roster rendered (truthiness check) while the DISPATCH button'sblocked !== nullguard read it as blocked — the JUMP panel's dispatch was permanently dead on an empty queue, i.e. in the state every one of those specs reaches (smoke 174/202/516, red on runs 396/399/400 with 300 swaitForResponsetimeouts). The fix coalesces the queued-jump search to null soblockedis strictlyQueueDto | null.Verification: full e2e suite green on the merged head (run 402 / job 413: 26/26, including the three formerly red specs, 5.7–6.9 s each; restart-persistence spec green); unit suite green (166 tests).
Tags: v0.10.0 →
9020a77, v0.10.1 →678cd48a.Deploy: PENDING — the deploy guard requires a clean main checkout, but
/home/krzyw/projects/sandbox/space-wandererhas untracked.opencode/anddocs/, so the first production deploy was skipped; https://space-wanderer.dev.kkhost.pl is still undeployed (404). To ship: reset the main checkout to origin/master (keeping the untracked files) and rundocker compose up -d --buildthere, then verify/api/version= 0.10.1.