Skip to content

reset-readiness: greenfield deploy profile + markets write-through fix (#8)#12

Merged
jdkajewski merged 1 commit into
jdkajewski/ts-rewrite-planfrom
dk-reset-readiness
Jun 20, 2026
Merged

reset-readiness: greenfield deploy profile + markets write-through fix (#8)#12
jdkajewski merged 1 commit into
jdkajewski/ts-rewrite-planfrom
dk-reset-readiness

Conversation

@jdkajewski

@jdkajewski jdkajewski commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Makes packages/bot production-ready to run LIVE at the next greenfield weekly reset — deployment polish, not new earners. A readiness pass confirmed all earner subsystems are wired and home/expansion auto-detect; this PR removes the remaining reset-specific footguns and ships a reset-agnostic launch profile.

1. Fix issue #8 — markets write-through

persistence.putMarkets() sent the bot's Record<wp, Market> straight to the wire, but PUT /markets (BulkPutBody) expects Array<{ waypoint, data }>400, and the call is fire-and-forget so it was silently dropped (no market snapshot ever persisted → crawler/market history lost on restart).

  • putMarkets now converts Record → Array<{waypoint, data}> before send.
  • The GET side mismatched too (the api returns Array<{waypoint, data, updatedAt}>, the bot typed it as a Record) — getMarkets()/getMarket() now reduce the array back into the Record the cache expects.
  • New contract test (persistence.markets.test.ts, 4 cases) validates the outgoing body exactly as BulkPutBody would, guards the old Record body as a regression, and round-trips GET so the bot↔api shapes can't drift again.

2. docker-compose — auto-detect home

  • Dropped SYSTEM: ${SYSTEM:-X1-PP30} from the bot environment: block so a fresh reset auto-detects home via resolveHome() instead of pinning the previous reset's system. (environment: overrides env_file:, so a pin there would clobber a per-profile value.)
  • Layered ./deploy/bot.greenfield.env as a second env_file: entry and documented the --env-file requirement for live runs.

3. Greenfield deploy profile

New deploy/bot.greenfield.env.example — a complete, reset-agnostic LIVE earner profile with no hardcoded system/waypoint/ship symbols:

  • DRY_RUN=0, token=PASTE_AT_RESET, API_BASE_URL=http://api:3000, SYSTEM unset (auto-detect).
  • Enables the self-provisioning earner stack: FLEET_SCALE, CONTRACTS, GATE_SUPPLY, MINE_FEED+MINE_EXPAND, GALAXY_CRAWL+AUTO_EXPAND — all of which auto-discover shipyards/tenders/outposts so no ship pins are needed. INPUT_FEED=0 (matches the battle-tested legacy profile).
  • Floors mirrored from the legacy overnight_experiment profile (MIN_NET=1200, GATE_CREDIT_FLOOR=900000, FLEET_SCALE_FLOOR=30000, …) with reset-specific pins stripped and greenfield-safe values chosen.
  • Issue-Value-weighted, lane-driven market scan budgeting (replace uniform 1:1 probe coverage) #2 scan-optimization levers (SCAN_*/COVERAGE_*/SCAN_BUDGET_*/FLEET_COVERAGE_*) left at default OFF — not needed to earn; enable + measure post-reset against the credits-per-request metric.
  • Runbook header with the exact tomorrow flow: register → paste token → docker compose --env-file deploy/bot.greenfield.env up --build.

The legacy deploy/bot.env.example is untouched.

4. NEGOTIATOR default — honest gap signal ⚠

shared/config.ts defaulted NEGOTIATOR to a reset-specific ship 'SPACEJAM-DK-2-15' — a greenfield footgun (CONTRACTS=1 would dock/negotiate against a ship that doesn't exist on a fresh reset). Changed the default to '' and guarded the new-contract negotiate call on a non-empty NEGOTIATOR so an empty value cleanly skips auto-negotiation.

Gap: with NEGOTIATOR empty the bot still accepts offered/pending contracts but cannot negotiate NEW ones — the profile can't know the agent's command ship pre-reset. The runbook instructs setting NEGOTIATOR=<AGENT>-1 post-register for sustained contract income. A future enhancement could auto-pick the command ship; flagged for review.

Calibration assumption

The live .mjs history (live-metrics.json) is issue-#2 scan/lane data and not relevant to greenfield earner floors, which come from the battle-tested legacy overnight_experiment profile. Referenced in the env header as a comment for later scan-lever tuning.

Verification

  • @st/shared build clean, @st/bot tsc --noEmit clean, eslint clean on changed files.
  • 269 bot tests pass (incl. 4 new markets contract tests), 18 api tests pass (after the normal prisma generate codegen step).

Scope boundary: does NOT touch the parked issue-#2 optimization PRs (#9, #10).

#8)

Make packages/bot production-ready for a fresh greenfield weekly reset.

Issue #8 — markets write-through:
- persistence.putMarkets() converted the bot's Record<wp,Market> straight to
  the wire, but PUT /markets (BulkPutBody) wants Array<{waypoint,data}> → 400,
  and the call is fire-and-forget so it was silently dropped (no snapshot ever
  persisted). Convert Record→array before send. The GET side mismatched too
  (api returns Array<{waypoint,data,updatedAt}>, bot typed it as Record) so
  getMarkets()/getMarket() now reduce the array back into the Record the cache
  expects. Added a contract test that validates the body shape exactly as
  BulkPutBody would (and guards the old Record body as a regression).

docker-compose:
- Dropped SYSTEM: ${SYSTEM:-X1-PP30} from the bot environment: block so a fresh
  reset auto-detects home via resolveHome() instead of pinning the old system.
  (environment: overrides env_file:, so a pin there clobbers a per-profile value.)
- Layered ./deploy/bot.greenfield.env as a second env_file: entry and documented
  the --env-file requirement for live runs.

Greenfield deploy profile:
- New deploy/bot.greenfield.env.example: a complete, reset-agnostic LIVE earner
  profile (no hardcoded system/waypoint/ship symbols). Enables the self-
  provisioning earner stack (FLEET_SCALE, CONTRACTS, GATE_SUPPLY, MINE_FEED/
  EXPAND, GALAXY_CRAWL + AUTO_EXPAND); battle-tested floors mirrored from the
  legacy overnight_experiment profile with reset-specific pins stripped; issue-#2
  scan-optimization levers left at default OFF; runbook header with the exact
  compose invocation.

NEGOTIATOR default:
- shared/config.ts NEGOTIATOR default was a reset-specific ship 'SPACEJAM-DK-2-15'
  — a greenfield footgun. Defaulted to '' and guarded the new-contract negotiate
  call on a non-empty NEGOTIATOR so an empty value cleanly skips auto-negotiation
  (the bot still accepts offered/pending contracts). Pin to the command ship
  post-register for sustained negotiation.

Verification: @st/shared build clean, @st/bot tsc --noEmit clean, eslint clean on
changed files, 269 bot tests pass (incl. 4 new markets contract tests), 18 api
tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jdkajewski jdkajewski merged commit 10b6a1b into jdkajewski/ts-rewrite-plan Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant