feat: Resources & Industry — per-region resource profiles + industry LLM lever (v0.36.0, #59) #70

Merged
kamilkrzywda merged 1 commits from feat/59-resources-industry into master 2026-10-15 20:27:18 +02:00
Owner

Summary

Implements Gitea issue #59: per-region synthesized 4-value resource profiles and a new industry LLM lever.

What's new

  • public/region-resources.json — 1,800 entries, each a { oil, iron, food, industry } 0–1 profile, built by the new deterministic, idempotent scripts/build-region-resources.mjs (FNV-1a hash × area factor).
  • server/regions.ts — hasResources() / resourceOf() optional-manifest loader (same pattern as centroids/geo).
  • shared/types.ts — RegionResources, IndustryType / INDUSTRY_TYPES / IndustryProject, GameState.industry.
  • shared/protocol.ts — IndustryOps, TurnResult.industry, deriveNationResources (area×population-weighted average, 2dp).
  • server/engine.ts — validateIndustryOps, applyIndustryOps (per-region SET; first-declared-type wins; invalid keys dropped), applyIndustryEffects (sole-owner-only economy boost: INDUSTRY_ECONOMY_BONUS = 1, +1 extra when region's industry value ≥ 0.5; 0/2+ owner regions kept but no boost; re-derive after), system + user prompt contract lines, resourceOf opt on runTurn, nationResources in user payload.
  • server/db.ts — legacy-row industry default migration.
  • server/stub.ts — stub returns industry: { projects: [] }; resources / industry added to StubPayload (never read).
  • server/index.ts — resourceOf wired to the jump route.
  • All existing test fixtures updated; new describe blocks in engine.test.ts, protocol.test.ts, regions.test.ts, db.test.ts.
  • CHANGELOG.md v0.36.0, AGENTS.md docs, package.json 0.36.0.

Design notes

  • No engine randomness; no @turf / @types/geojson from .ts; shared/ remains runtime-dep-free.
  • The stub never declares a project, so e2e (CI, LLM_STUB=1) is unaffected.
  • A project on a region with 0 or 2+ owners is kept in state.industry but yields no boost.
  • Per-region SET: a region that already hosts a project is untouched (re-declare is a no-op, type is never replaced).

Fixes #59

## Summary Implements Gitea issue #59: per-region synthesized 4-value resource profiles and a new `industry` LLM lever. ### What's new - **`public/region-resources.json`** — 1,800 entries, each a `{ oil, iron, food, industry }` 0–1 profile, built by the new deterministic, idempotent `scripts/build-region-resources.mjs` (FNV-1a hash × area factor). - **`server/regions.ts`** — `hasResources()` / `resourceOf()` optional-manifest loader (same pattern as centroids/geo). - **`shared/types.ts`** — `RegionResources`, `IndustryType` / `INDUSTRY_TYPES` / `IndustryProject`, `GameState.industry`. - **`shared/protocol.ts`** — `IndustryOps`, `TurnResult.industry`, `deriveNationResources` (area×population-weighted average, 2dp). - **`server/engine.ts`** — `validateIndustryOps`, `applyIndustryOps` (per-region SET; first-declared-type wins; invalid keys dropped), `applyIndustryEffects` (sole-owner-only economy boost: `INDUSTRY_ECONOMY_BONUS = 1`, +1 extra when region's `industry` value ≥ 0.5; 0/2+ owner regions kept but no boost; re-derive after), system + user prompt contract lines, `resourceOf` opt on `runTurn`, `nationResources` in user payload. - **`server/db.ts`** — legacy-row `industry` default migration. - **`server/stub.ts`** — stub returns `industry: { projects: [] }`; `resources` / `industry` added to `StubPayload` (never read). - **`server/index.ts`** — `resourceOf` wired to the jump route. - All existing test fixtures updated; new describe blocks in `engine.test.ts`, `protocol.test.ts`, `regions.test.ts`, `db.test.ts`. - `CHANGELOG.md` v0.36.0, `AGENTS.md` docs, `package.json` 0.36.0. ### Design notes - No engine randomness; no `@turf` / `@types/geojson` from `.ts`; `shared/` remains runtime-dep-free. - The stub never declares a project, so e2e (CI, `LLM_STUB=1`) is unaffected. - A project on a region with 0 or 2+ owners is **kept** in `state.industry` but yields no boost. - Per-region SET: a region that already hosts a project is untouched (re-declare is a no-op, type is never replaced). Fixes #59
kamilkrzywda added 1 commit 2026-10-15 20:23:30 +02:00
- scripts/build-region-resources.mjs: deterministic, idempotent builder →
  public/region-resources.json (1,800 entries; FNV-1a hash × area factor, 0–1, 2dp)
- server/regions.ts: hasResources()/resourceOf() optional-manifest loader
- shared/types.ts: RegionResources, IndustryType/INDUSTRY_TYPES, IndustryProject,
  GameState.industry
- shared/protocol.ts: IndustryOps, TurnResult.industry, deriveNationResources
  (area×population-weighted average, 2dp)
- server/engine.ts: isIndustryType, validateIndustryOps, applyIndustryOps
  (per-region SET, first-declared-type wins), applyIndustryEffects
  (INDUSTRY_ECONOMY_BONUS=1, +1 when region industry≥0.5; sole-owner only;
  0/2+ owner regions kept but no boost; re-derive after), system+user prompt
  contract lines, runTurn resourceOf opt, nationResources in user payload
- server/db.ts: legacy-row industry default migration
- server/stub.ts: industry:{projects:[]} in stub result; resources/industry
  in StubPayload (never read)
- server/index.ts: resourceOf wired to jump route
- All test fixtures updated; new describe blocks in engine.test.ts,
  protocol.test.ts, regions.test.ts, db.test.ts
- CHANGELOG.md v0.36.0, AGENTS.md docs, package.json 0.36.0

Fixes #59
kamilkrzywda scheduled this pull request to auto merge when all checks succeed 2026-10-15 20:27:16 +02:00
kamilkrzywda merged commit 0fd8981452 into master 2026-10-15 20:27:18 +02:00
kamilkrzywda deleted branch feat/59-resources-industry 2026-10-15 20:27:18 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OpenCode/History#70