Skip to content

feat(openworlds): seed BG world_graph edges with route_kind (Closes #381) - #391

Closed
100yenadmin wants to merge 1 commit into
mainfrom
feat/381-route-kind-edges
Closed

feat(openworlds): seed BG world_graph edges with route_kind (Closes #381)#391
100yenadmin wants to merge 1 commit into
mainfrom
feat/381-route-kind-edges

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented May 30, 2026

Copy link
Copy Markdown
Member

TL;DR

Loop-10 verification of #261 found the atlas/world_graph pipeline already carries route_kind end-to-end — model, loader, viewer projection, viewer branching all exist — but the baldurs-gate world has zero world_graph edges, so every BG inter-district connection projects as the same untyped default stroke. This PR delivers the content, plus the two adjacent gaps the Loop-10 sub-agent flagged.

Closes

What this lands

1. servers/engine/models.pyWorldGraphEdge.route_kind Literal

Extended by 3 members. The existing 7 kinds + default "road" are unchanged (zero behavior change for any existing authored content).

New kind Why
ferry Was already a dead branch in screen-map.jsx edgeStyle — viewer styled it, model rejected it on author. Now authorable.
bridge Wyrm's Crossing over the Chionthar is canonically a bridge, not a road. First-class kind so styling can mark it.
underground Underdark passages, sewers, Bhaal Temple stairs. Lands ahead of #380 so the data surface is ready for those POIs.

2. content/worlds/baldurs-gate/world.json — NEW world_graph block

Six directed edges, one per canonical region-pair:

From → To Kind Minutes Difficulty Danger Lore tags
Lower City → Upper City street 8m easy 1 urban, uphill, fist-checkpoint
Lower City → Outer City street 12m easy 2 urban, basilisk-gate, slums-edge
Outer City → Wyrm's Crossing bridge 18m easy 2 chionthar, fist-toll, wyrms-rock
Wyrm's Crossing → Elturel road 24h normal 3 risen-road, south, hellrider-patrol
Wyrm's Crossing → Reithwin road 36h hard 5 shadow-cursed, north, lifting
Wyrm's Crossing → Candlekeep road 96h normal 2 coast-road, west, avowed-watch

All 6 verified against canonical Location.connections — the _seed_world_graph loader's "edge must reference an existing connection in either direction" guard passes for every edge (validated standalone via the loader's exact predicate).

3. viewer/openworlds/screen-map.jsxedgeStyle extension

Existing styled 3 kind-buckets (street/road, river/ferry/sea, default). The Literal now supports 10. Added branches:

Kind Style Reads as
bridge Thicker amber-brown solid (width 1.05) Load-bearing crossing
underground / passage Tight-dotted dark brown "You go down, not across"
portal Violet dashed Extraplanar / arcane
trail Lighter brown, looser-dashed "You'll get there, just not quickly"

The pre-existing high-danger override (danger >= 6) still wins regardless of kind — that's the right precedence (player should see "dangerous" before "what kind of road").

Why grouped, not 3 PRs

The 3 changes form one logical unit:

  • The Literal opens what authors can write
  • The world.json exercises that authorship
  • The edgeStyle makes the new kinds visually distinguishable

Shipping any 1 or 2 leaves the surface incomplete. Authoring bridge without a distinct style means the player can't tell the bridge from a road; styling bridge without authoring leaves the new branch dead.

Verification

File Check Result
world.json json.load() parses ✅ 26 top-level keys (was 25), 6 edges
world.json All edges satisfy loader's connection guard ✅ 6/6
models.py ast.parse()
screen-map.jsx Brace + paren balance ✅ 450/450, 601/601

Acceptance criteria (per #381)

Out of scope

Collision audit

DO NOT MERGE yet

Per owner direction. Ready for review.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added world graph connectivity for Baldur's Gate, defining travel routes between regions (lower city, upper city, outer city, Wyrm's Crossing, Elturel, Reithwin, Candlekeep) with route metadata including travel time and difficulty.
    • Introduced new route types (ferry, bridge, underground) with distinct visual styling on the map interface.

Review Change Stack

)

Loop-10 verification of #261: the atlas/world_graph pipeline already
carries route_kind end-to-end (WorldGraphEdge model + _seed_world_graph
loader + _atlas_edge_payload projection + edgeStyle viewer branching)
but the baldurs-gate world has ZERO world_graph edges — so every BG
inter-district connection projects as the same untyped default stroke.

This PR delivers the content + the two adjacent gaps the Loop-10
sub-agent flagged.

What this lands
---------------

1. servers/engine/models.py (WorldGraphEdge.route_kind Literal)
   Extends the Literal to include "ferry", "bridge", "underground":
   - "ferry": was already a dead branch in screen-map.jsx edgeStyle —
     the viewer styled it, but the model rejected it on author. Now
     authorable.
   - "bridge": Wyrm's Crossing over the Chionthar (the canonical BG
     load-bearing crossing) is structurally a bridge, not a road.
     First-class kind so the styling can mark it as distinct.
   - "underground": Underdark passages, sewers, Bhaal Temple stairs.
     Lands ahead of #380 (BG canon POIs incl. Underdark) so the data
     surface is ready.
   The existing 7 kinds are unchanged + default value "road" preserved
   — no behavior change for any existing authored content (which is
   currently zero edges across all worlds, but the contract is intact).

2. content/worlds/baldurs-gate/world.json (NEW world_graph block)
   Authors 6 directed edges, one per canonical region-pair, each with
   minutes / difficulty / danger / tags grounded in BG3 + Forgotten
   Realms canon:
     loc-lower-city     → loc-upper-city      street  8m  easy d=1
       tags: urban, uphill, fist-checkpoint
     loc-lower-city     → loc-outer-city      street  12m easy d=2
       tags: urban, basilisk-gate, slums-edge
     loc-outer-city     → loc-wyrms-crossing  bridge  18m easy d=2
       tags: chionthar, fist-toll, wyrms-rock
     loc-wyrms-crossing → loc-elturel         road    24h normal d=3
       tags: risen-road, south, hellrider-patrol
     loc-wyrms-crossing → loc-reithwin        road    36h hard d=5
       tags: shadow-cursed, north, lifting
     loc-wyrms-crossing → loc-candlekeep      road    96h normal d=2
       tags: coast-road, west, avowed-watch
   All 6 verified against canonical Location.connections — the
   _seed_world_graph loader's "edge must reference an existing
   connection in either direction" guard PASSes for every edge
   (verified standalone via the loader's exact predicate).

3. viewer/openworlds/screen-map.jsx (edgeStyle extension)
   The existing edgeStyle had styles for 3 kinds (street/road, river/
   ferry/sea, default). The Literal supports 7 (now 10). This PR adds
   styles for the remaining kinds so atlas reading isn't ambiguous:
     - bridge        : thicker amber-brown solid  (load-bearing crossing)
     - underground   : tight-dotted dark brown    (you go down)
     - passage       : same as underground
     - portal        : violet dashed              (extraplanar)
     - trail         : light brown looser-dashed  (wilds-grade path)
   The pre-existing high-danger override (danger >= 6) still wins
   regardless of kind — that's the right precedence (the player
   should see "dangerous" before "what kind of road").

Why grouped, not 3 PRs
----------------------

The 3 changes form one logical unit: the Literal opens what authors
can write, the world.json exercises that authorship, the edgeStyle
makes the new kinds visually distinguishable. Shipping any 1 or 2
without the third leaves the surface incomplete (e.g. authoring
"bridge" without a distinct style means the player can't tell the
bridge from a road; styling "bridge" without authoring leaves the
new branch dead).

Verification
------------

- world.json: `json.load()` passes; 26 top-level keys (was 25);
  6 edges; 3 route_kinds used (street, road, bridge). Validated all
  6 edges satisfy the loader's "edge.to_id in src.connections OR
  edge.from_id in dst.connections" guard.
- models.py: `ast.parse()` passes. Literal extended by 3 members,
  default unchanged.
- screen-map.jsx: brace balance 450/450, paren balance 601/601.
  Existing kinds (street, road, river, ferry, sea) styled exactly as
  before — diff is purely additive new branches.

Acceptance criteria (per #381)
------------------------------

- [x] world_graph block authored for the BG world (zero before, 6 now)
- [x] route_kind values match the AC's intended palette
      (street, road, bridge in this PR; ferry/sea/river already
      supported; underground + portal + trail ready for #380's POIs)
- [x] Literal extended to include "ferry" (closing the existing dead
      branch in edgeStyle) + "bridge" + "underground"
- [x] edgeStyle extended to give each kind a distinct visual signal
- [x] Edges validated against canonical Location.connections — no
      drift between regions[] and world_graph

Out of scope
------------

- New POIs / regions (#380) — required for portal + underground edges
  to actually appear; this PR makes the Literal ready, the seed waits
- Edge metadata for non-BG worlds — pure-data work per world
- A symmetric-edges convention (today: 6 directed edges; could be 12
  for full symmetry, but viewer renders fine either way)

Refs
----

- Closes #381 (Loop-10 follow-up to #261)
- Parent #261 (atlas-seed, PR #371 closed the discovered-tier strand)
- Builds toward #380 (BG POIs — Steel Watch, Underdark, Bhaal Temple,
  Avernus portal — which will exercise the new "underground" + "portal"
  Literal members)
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR extends the world graph system to support new strategic route types (ferry, bridge, underground) and applies them to the Baldur's Gate world. The schema is broadened to validate these types, the world data is seeded with region-connecting edges, and the map renderer is updated to style these routes distinctly.

Changes

World Graph Connectivity

Layer / File(s) Summary
Route type schema extension
servers/engine/models.py
WorldGraphEdge.route_kind Literal enum is expanded to accept ferry, bridge, and underground in addition to existing street, road, trail, sea, river, passage, and portal types.
World graph data and edge styling
content/worlds/baldurs-gate/world.json, viewer/openworlds/screen-map.jsx
Baldur's Gate world.json introduces a world_graph section with directed edges between regions (lower city, upper city, outer city, Wyrm's Crossing, Elturel, Reithwin, Candlekeep) using the new route types. The map renderer edgeStyle function adds dedicated stroke, color, and dash patterns for bridge, underground, passage, portal, and trail routes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related issues

  • electricsheephq/WorldOS#381: The changes directly extend WorldGraphEdge.route_kind and add world_graph seeding for Baldur's Gate as outlined in the issue.

Possibly related PRs

  • electricsheephq/WorldOS#191: This PR builds directly on the WorldGraph models, seeding, and atlas projection infrastructure established in the retrieved PR.

Suggested labels

enhancement, tier-1

Poem

🐰 The routes now shimmer with three new hues,
Ferry, bridge, and underground mews,
World graphs spring alive with fresh strokes,
Baldur's Gate whispers its hidden folks!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding route_kind support and Baldur's Gate world_graph edges, which aligns with the primary objective and file modifications.
Description check ✅ Passed The PR description is comprehensive and well-structured with TL;DR, objectives, detailed breakdown of each file change, verification steps, acceptance criteria, and scope notes. However, the Licensing/CLA checklist section from the template is completely missing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
content/worlds/baldurs-gate/world.json (1)

56-63: ⚡ Quick win

Consider adding reverse-direction edges for complete travel metadata.

The world_graph defines 6 directed edges, but each corresponds to a bidirectional connection in the Location.connections (lines 45-51). This means return journeys exist but lack metadata.

For example:

  • Lower City → Upper City has metadata (8 minutes, street, easy, danger 1)
  • Upper City → Lower City has no metadata (only the connection exists)

Since return journeys often have different characteristics (e.g., downhill vs uphill, different timing), consider whether reverse edges should be added with appropriate metadata, or document if the one-way metadata is intentional.

Example: adding the reverse edge for Upper → Lower City
       {"from_id": "loc-lower-city",      "to_id": "loc-upper-city",      "route_kind": "street", "minutes":    8, "difficulty": "easy",   "danger": 1, "tags": ["urban", "uphill", "fist-checkpoint"]},
+      {"from_id": "loc-upper-city",      "to_id": "loc-lower-city",      "route_kind": "street", "minutes":    6, "difficulty": "easy",   "danger": 1, "tags": ["urban", "downhill", "basilisk-gate"]},
       {"from_id": "loc-lower-city",      "to_id": "loc-outer-city",      "route_kind": "street", "minutes":   12, "difficulty": "easy",   "danger": 2, "tags": ["urban", "basilisk-gate", "slums-edge"]},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/worlds/baldurs-gate/world.json` around lines 56 - 63, The edges array
defines only one direction for connections (e.g.,
{"from_id":"loc-lower-city","to_id":"loc-upper-city",...}) while
Location.connections imply bidirectional travel; add corresponding
reverse-direction edge objects for each route (e.g., from_id: "loc-upper-city"
to_id: "loc-lower-city") with appropriate metadata (minutes, route_kind,
difficulty, danger, tags) reflecting return-trip differences (downhill,
faster/slower, differing danger), or if one-way metadata is intentional, add a
clear comment/documentation entry stating that edges are directional and return
trips use default/implicit values; update the edges array to include reverse
entries for loc-lower-city↔loc-upper-city, loc-lower-city↔loc-outer-city,
loc-outer-city↔loc-wyrms-crossing, loc-wyrms-crossing↔loc-elturel,
loc-wyrms-crossing↔loc-reithwin, and loc-wyrms-crossing↔loc-candlekeep.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@content/worlds/baldurs-gate/world.json`:
- Around line 56-63: The edges array defines only one direction for connections
(e.g., {"from_id":"loc-lower-city","to_id":"loc-upper-city",...}) while
Location.connections imply bidirectional travel; add corresponding
reverse-direction edge objects for each route (e.g., from_id: "loc-upper-city"
to_id: "loc-lower-city") with appropriate metadata (minutes, route_kind,
difficulty, danger, tags) reflecting return-trip differences (downhill,
faster/slower, differing danger), or if one-way metadata is intentional, add a
clear comment/documentation entry stating that edges are directional and return
trips use default/implicit values; update the edges array to include reverse
entries for loc-lower-city↔loc-upper-city, loc-lower-city↔loc-outer-city,
loc-outer-city↔loc-wyrms-crossing, loc-wyrms-crossing↔loc-elturel,
loc-wyrms-crossing↔loc-reithwin, and loc-wyrms-crossing↔loc-candlekeep.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ce1b69e-9a68-4cbd-9036-c48c10c1216c

📥 Commits

Reviewing files that changed from the base of the PR and between bb1870d and 9361c5a.

📒 Files selected for processing (3)
  • content/worlds/baldurs-gate/world.json
  • servers/engine/models.py
  • viewer/openworlds/screen-map.jsx

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