Skip to content

Feat/2.29 - #412

Merged
ElderEvil merged 9 commits into
masterfrom
feat/2.29
Aug 10, 2026
Merged

Feat/2.29#412
ElderEvil merged 9 commits into
masterfrom
feat/2.29

Conversation

@ElderEvil

@ElderEvil ElderEvil commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Locations now unlock after meaningful interaction with dwellers, with notifications when new areas are discovered.
    • Map markers and details clearly distinguish locked and unlocked locations.
    • Added an option to show only unlocked map locations.
    • Empty maps now offer a shortcut to recruit dwellers.
  • Bug Fixes
    • Map data refreshes automatically after chat interactions.
    • Improved login submission feedback and prevented duplicate submissions.
  • UI Improvements
    • Added loading skeletons and improved mobile layouts for dashboards, maps, and dweller views.

ElderEvil and others added 7 commits August 10, 2026 20:33
- pnpm-workspace.yaml: add audit overrides for transitive CVEs
  (nanoid, undici, js-yaml, postcss, brace-expansion, esbuild, dompurify)
- Restore package.json/pnpm-lock.yaml from master to resolve stash pop conflicts
- Login: isLoading state, disabled button, AUTHENTICATING text, error-pulse animation, spacing/divider fixes
- Dwellers: HappinessDashboard loading prop + skeleton, tighter spacing, 480px single-column grid
- Map: marker hover glow, top-right zoom controls, responsive legend, empty-state Recruit CTA
- Backend: add is_unlocked bool to DwellerLocationBase + Alembic migration with index

Verification: lint/typecheck/tests pass, alembic head 0ca13298230f, DB column/index confirmed
- Add is_unlocked to DwellerRef and WastelandLocationWithDwellers schemas
- Add unlock_places_for_dweller CRUD and count_user_messages_to_dweller helper
- Trigger unlock after 3+ user messages in chat_service (process_text_message + stream_response)
- Propagate is_unlocked through map_service with optional unlocked_only filter
- Add unlocked_only query param to map endpoint
- Add tests for unlock behavior, CRUD, and map service filtering

Verification: 1496 passed, 2 skipped (32.92s)
- Add is_unlocked to map models (generated types now include it)
- MapMarker: locked state (lock-question icon, dashed outline, 50% opacity, Unknown Location label)
- MarkerDetailModal: locked placeholder with hint to chat with dweller
- WorldMap: pass is_unlocked to markers
- Map store: unlockedPlacesCount getter + refreshMap action
- Chat integration: trigger map refresh after send, watch unlock count, toast on new locations
- Add/update unit tests for MapMarker, MarkerDetailModal, DwellerChat

Verification: lint/typecheck/tests pass (1121 passed, 1 skipped)
- Remove unsupported --skip-types-generate flag from webServer command
- Update interaction.spec.ts side-panel nav items to match current UI
  (remove 'Happiness', add 'Map')

Verification: 163 Playwright e2e tests pass
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ElderEvil, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 364e1b0e-a481-4f57-baa9-6be476a468fb

📥 Commits

Reviewing files that changed from the base of the PR and between 571cfee and 03c5d26.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • backend/app/crud/wasteland_location.py
  • backend/app/services/chat_service.py
  • backend/app/tests/test_services/test_map_service.py
  • frontend/playwright.config.ts
  • frontend/pnpm-workspace.yaml
  • frontend/src/modules/chat/components/DwellerChat.vue
  • frontend/src/modules/dwellers/views/DwellersView.vue
  • frontend/src/modules/map/components/MarkerDetailModal.vue
  • frontend/src/modules/map/stores/map.ts
  • frontend/tests/unit/components/chat/DwellerChat.test.ts
📝 Walkthrough

Walkthrough

The change adds persisted dweller-location unlock state. Chat activity unlocks linked locations after three user messages. Backend map responses, frontend map rendering, chat refresh behavior, loading states, responsive layouts, and frontend tooling are updated.

Changes

Location unlocking

Layer / File(s) Summary
Persisted unlock state and chat threshold
backend/app/alembic/versions/..., backend/app/models/wasteland_location.py, backend/app/schemas/wasteland_location.py, backend/app/crud/..., backend/app/services/chat_service.py, backend/app/tests/test_crud/..., backend/app/tests/test_services/test_chat_service.py
The database and models store is_unlocked. Chat message counts trigger bulk unlocking after three user messages. CRUD and chat tests cover unlocking, empty results, and idempotency.
Unlock-aware map responses
backend/app/api/v1/endpoints/map.py, backend/app/services/map_service.py, backend/app/tests/test_services/test_map_service.py
The map API accepts unlocked_only. Map locations and dweller references expose unlock state. Locked non-home locations can be filtered out.
Chat-triggered map refresh
frontend/src/modules/chat/..., frontend/src/modules/map/stores/map.ts, frontend/tests/unit/components/chat/DwellerChat.test.ts
Chat actions refresh the map after sending messages. The chat view tracks newly unlocked locations and displays a toast.
Locked map presentation
frontend/src/modules/map/components/..., frontend/tests/unit/components/map/*
Locked markers show an unknown-location state. Detail modals show a locked placeholder. Vault markers retain their names. Tests cover both states.

Frontend UI and tooling updates

Layer / File(s) Summary
Authentication and loading feedback
frontend/src/modules/auth/components/LoginFormTerminal.vue, frontend/src/modules/dwellers/views/DwellersView.vue, frontend/src/modules/vault/components/HappinessDashboard.vue
The login form shows an authentication state. Dashboard views render skeleton placeholders. Dweller layout spacing and mobile columns are updated.
Map navigation and responsive presentation
frontend/src/modules/map/components/MapLegend.vue, frontend/src/modules/map/components/WorldMap.vue, frontend/src/modules/map/views/MapView.vue
The map legend gains mobile styling. Empty maps link to the radio page. Zoom controls move to the right.
Development tooling and navigation checks
frontend/playwright.config.ts, frontend/pnpm-workspace.yaml, frontend/tests/e2e/interaction.spec.ts
Playwright starts the development server without the type-generation skip flag. Dependency release-age and override rules are added. Navigation tests expect Map.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • ElderEvil/falloutProject#401: This change extends the world-map models, schemas, CRUD, map service/API, frontend map components, and map store introduced there.

Sequence Diagram(s)

sequenceDiagram
  participant Dweller
  participant ChatService
  participant CRUDChatMessage
  participant CRUDWastelandLocation
  participant MapService
  Dweller->>ChatService: Send messages
  ChatService->>CRUDChatMessage: Count user messages
  CRUDChatMessage-->>ChatService: Return count
  ChatService->>CRUDWastelandLocation: Unlock linked locations at count three
  ChatService-->>Dweller: Return chat response
  Dweller->>MapService: Refresh vault map
  MapService-->>Dweller: Return updated unlock states
Loading
sequenceDiagram
  participant DwellerChat
  participant useChatActions
  participant useMapStore
  participant MapView
  DwellerChat->>useChatActions: Send text message
  useChatActions-->>DwellerChat: Complete chat action
  DwellerChat->>useChatActions: Call refreshAfterChat
  useChatActions->>useMapStore: Refresh map for vault
  useMapStore-->>MapView: Update locations and unlockedPlacesCount
  MapView-->>DwellerChat: Show newly uncovered location toast
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title identifies a feature branch but does not describe the primary changes for unlocking wasteland locations and updating map behavior. Replace the branch identifier with a concise description, such as "Add progressive wasteland location unlocking and map visibility".
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/2.29

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/modules/map/components/MarkerDetailModal.vue (1)

69-90: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the modal locked state consistent with map markers.

isLocked treats home_vault as locked when is_unlocked is false. This hides Home Vault details, although MapMarker explicitly keeps home-vault markers unlocked and the map service retains them without DwellerLocation references. The modal title also still uses placeName, so it exposes a locked location name above the placeholder.

Exclude home_vault from isLocked. Bind the modal title to Unknown Location when a non-home location is locked.

Proposed fix
-const isLocked = computed(() => props.location !== null && !props.location.is_unlocked)
+const isLocked = computed(
+  () =>
+    props.location !== null &&
+    props.location.type !== 'home_vault' &&
+    !props.location.is_unlocked
+)
+const modalTitle = computed(() => (isLocked.value ? 'Unknown Location' : placeName.value))
-  <UModal v-model="isOpen" :title="placeName" size="lg">
+  <UModal v-model="isOpen" :title="modalTitle" size="lg">
🤖 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 `@frontend/src/modules/map/components/MarkerDetailModal.vue` around lines 69 -
90, Update the isLocked computed value to exclude locations whose type is
home_vault, matching MapMarker behavior. Change the UModal title binding to
display “Unknown Location” for locked non-home locations while preserving
placeName for unlocked and home-vault locations.
🧹 Nitpick comments (1)
frontend/playwright.config.ts (1)

19-19: 🩺 Stability & Availability | 🔵 Trivial

Verify backend startup before running E2E tests.

pnpm run dev runs types:generate first. That script fetches http://localhost:8000/api/v1/openapi.json. This Playwright configuration starts only the frontend server on port 5173. If CI does not start the backend separately, Playwright fails before any test runs. Confirm the backend startup and health-check order. (raw.githubusercontent.com)

🤖 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 `@frontend/playwright.config.ts` at line 19, Update the Playwright webServer
configuration around the dev command to ensure the backend is started and
healthy before running the frontend’s types:generate step. Preserve the existing
frontend startup on port 5173, and configure the startup/health-check order so
the OpenAPI endpoint on localhost:8000 is available before E2E tests begin.
🤖 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.

Inline comments:
In `@backend/app/crud/wasteland_location.py`:
- Around line 205-210: Update unlock_places_for_dweller so its DwellerLocation
update filters for the given dweller_id and is_unlocked == false before setting
is_unlocked to true, preserving the returned rowcount and commit behavior.

In `@backend/app/services/chat_service.py`:
- Around line 486-495: Update _maybe_unlock_places to catch unexpected errors
from counting or unlocking places, roll back the database session when needed,
and log the failure with logger.exception(...). Keep this helper best-effort by
preventing the exception from propagating so non-streaming responses succeed and
streaming flows can emit done.
- Line 486: Update the new _maybe_unlock_places method signature to
type-annotate dweller with the concrete type returned by get_full_info, or
change the parameter to dweller_id: UUID4 and adjust the implementation
accordingly; keep the existing behavior unchanged.

In `@frontend/pnpm-workspace.yaml`:
- Around line 33-36: Update the minimumReleaseAgeExclude entries for dompurify
and js-yaml to exact audited package versions rather than bare package names,
and align the pnpm override targets with those exact versions. Preserve the
existing esbuild configuration and ensure future releases remain subject to the
seven-day delay.

In `@frontend/src/modules/chat/components/DwellerChat.vue`:
- Line 107: In the location-uncovered notification flow, split the overlong
toast.success expression by extracting the count difference and plural suffix
into local variables before constructing the message. Keep the existing
singular/plural behavior and notification text unchanged.
- Around line 103-110: Initialize a map-count baseline before chat messages are
loaded, and update the watcher around mapStore.unlockedPlacesCount so the first
response from an empty store is treated as initialization rather than a new
unlock. Suppress the toast for that initial map response, while preserving
notifications for subsequent count increases.
- Around line 112-115: Update the voice-message flow to call refreshAfterChat
after sendAudioMessage completes successfully, matching handleSendMessage’s
behavior. Locate the sendAudioMessage handler and preserve existing error
handling while ensuring successful voice messages refresh the map immediately.

In `@frontend/src/modules/dwellers/views/DwellersView.vue`:
- Around line 338-343: Update the DwellersView dashboard branch to remain in its
loading state until currentVault, dwellerStore.allDwellers, and
incidentStore.activeIncidents have finished loading. Track or reuse the relevant
fetch-state signals from the mounted data-loading flow, use them in the
v-if/loading behavior, and replace the hard-coded HappinessDashboard
:loading="false" value with the combined readiness state.

In `@frontend/src/modules/map/stores/map.ts`:
- Around line 97-99: Update the catch block in the map refresh flow to capture
the caught error and, when gen matches _pollGeneration, call handleStoreError
with post-chat refresh context and assign the resulting error to error; preserve
the stale-generation early return so outdated requests remain ignored.

In `@frontend/tests/unit/components/chat/DwellerChat.test.ts`:
- Around line 119-126: Wrap mock values referenced by vi.mock factories in
vi.hoisted, including mockToastSuccess, mockFetchRooms, the exploration mocks,
and mockRefreshMap. Update the affected vi.mock factories to use the hoisted
values while preserving their existing behavior and interfaces.

---

Outside diff comments:
In `@frontend/src/modules/map/components/MarkerDetailModal.vue`:
- Around line 69-90: Update the isLocked computed value to exclude locations
whose type is home_vault, matching MapMarker behavior. Change the UModal title
binding to display “Unknown Location” for locked non-home locations while
preserving placeName for unlocked and home-vault locations.

---

Nitpick comments:
In `@frontend/playwright.config.ts`:
- Line 19: Update the Playwright webServer configuration around the dev command
to ensure the backend is started and healthy before running the frontend’s
types:generate step. Preserve the existing frontend startup on port 5173, and
configure the startup/health-check order so the OpenAPI endpoint on
localhost:8000 is available before E2E tests begin.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 796022e9-71c2-41d5-b438-354089edb683

📥 Commits

Reviewing files that changed from the base of the PR and between deb5646 and 571cfee.

⛔ Files ignored due to path filters (2)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/src/core/types/api.generated.ts is excluded by !**/*.generated.*
📒 Files selected for processing (29)
  • backend/app/alembic/versions/2026_08_10_0001-0ca13298230f_add_dweller_location_is_unlocked.py
  • backend/app/api/v1/endpoints/map.py
  • backend/app/crud/chat_message.py
  • backend/app/crud/wasteland_location.py
  • backend/app/models/wasteland_location.py
  • backend/app/schemas/wasteland_location.py
  • backend/app/services/chat_service.py
  • backend/app/services/map_service.py
  • backend/app/tests/test_crud/test_wasteland_location.py
  • backend/app/tests/test_services/test_chat_service.py
  • backend/app/tests/test_services/test_map_service.py
  • frontend/playwright.config.ts
  • frontend/pnpm-workspace.yaml
  • frontend/src/modules/auth/components/LoginFormTerminal.vue
  • frontend/src/modules/chat/components/DwellerChat.vue
  • frontend/src/modules/chat/components/DwellerChatPage.vue
  • frontend/src/modules/chat/composables/useChatActions.ts
  • frontend/src/modules/dwellers/views/DwellersView.vue
  • frontend/src/modules/map/components/MapLegend.vue
  • frontend/src/modules/map/components/MapMarker.vue
  • frontend/src/modules/map/components/MarkerDetailModal.vue
  • frontend/src/modules/map/components/WorldMap.vue
  • frontend/src/modules/map/stores/map.ts
  • frontend/src/modules/map/views/MapView.vue
  • frontend/src/modules/vault/components/HappinessDashboard.vue
  • frontend/tests/e2e/interaction.spec.ts
  • frontend/tests/unit/components/chat/DwellerChat.test.ts
  • frontend/tests/unit/components/map/MapMarker.test.ts
  • frontend/tests/unit/components/map/MarkerDetailModal.test.ts

Comment thread backend/app/crud/wasteland_location.py
Comment thread backend/app/services/chat_service.py Outdated
Comment thread backend/app/services/chat_service.py Outdated
Comment thread frontend/pnpm-workspace.yaml Outdated
Comment thread frontend/src/modules/chat/components/DwellerChat.vue
Comment thread frontend/src/modules/chat/components/DwellerChat.vue Outdated
Comment thread frontend/src/modules/chat/components/DwellerChat.vue
Comment thread frontend/src/modules/dwellers/views/DwellersView.vue
Comment thread frontend/src/modules/map/stores/map.ts Outdated
Comment thread frontend/tests/unit/components/chat/DwellerChat.test.ts Outdated
@ElderEvil
ElderEvil merged commit 42efca3 into master Aug 10, 2026
4 checks passed
@ElderEvil
ElderEvil deleted the feat/2.29 branch August 11, 2026 06:50
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