map/archive/generated-history/STEP17_NOTES.md
2026-08-08 17:41:30 +09:00

4.9 KiB

Step 17 — Alternative preview / apparent interruption fix

Diagnosis

The Step 16 worker move removed the explicit UI-thread fallback, but it did not fix two UI semantics that could make a completed Alternative request look as if nothing had happened.

  1. Expansion quality selection internally searched consecutive terrain variants. A request for variant N could evaluate N, N+1 (and sometimes N+2), while the next Alternative request for N+1 evaluated an overlapping set. Both clicks could therefore select the same internal terrain variant.
  2. generatePatch() could silently rerun the complete patch once after a quality/seam rejection. This made one Alternative click take roughly one or two complete patch attempts depending on the result. On a slow machine that produces the observed large wall-time variation and can cross an external/browser execution limit.
  3. If an Alternative failed, the previous pending preview stayed on screen, but the failure message was transient. This looked like a successful generation that was not reflected.
  4. Renderer raster caches inferred freshness from map metadata. There was no explicit preview revision in the key.
  5. Patch controls stayed usable while a worker job was active, so repeated clicks could enqueue work and make completion ownership ambiguous.
  6. The patch worker was reused after large jobs, allowing a high-water heap to survive across repeated Alternatives.

Changes

One Alternative click now means one exact variant

Interactive patch generation passes:

  • qualityTerrainAttempts: 1
  • maxQualityRetries: 0

mapPatch.js now supports an explicit terrain-quality attempt count. The default non-interactive behavior remains unchanged; only the UI Alternative path uses the one-variant policy.

This removes overlapping internal candidate sets. If variant N fails the quality gate, it is rejected and the user can request N+1; the UI no longer silently spends another whole-patch attempt on a different hidden variant.

Preview freshness is explicit

Every successful preview receives a monotonically increasing world.renderRevision and its requested previewVariant.

worldViewport.js propagates those values and renderer.js includes them in the stable raster cache prefix. A newly returned preview therefore cannot reuse a terrain/urban/prefecture-fill cache entry from an older preview merely because its dimensions and field types are the same.

Verify that a preview actually differs

Before displaying a successful worker result, app.js compares the committed and preview worlds over the patch write area and counts:

  • changed cells
  • terrain changed cells (elevation, sea, landuse, populationDensity)
  • administration changed cells (adminId, municipalityId, prefectureRegionId)

The persistent patch status reports those counts. If a result is genuinely identical, the UI says so explicitly instead of implying that a visual update was lost.

Unambiguous rendering

After a successful patch worker result, the app performs one immediate full redraw of the new pending world. The previous fast-redraw + delayed-full-redraw pair was removed from this path.

The progress text now distinguishes generation from rendering and reports both generation and render wall time.

Failure remains visible

If an Alternative is rejected or the worker fails, the patch status now says either:

  • no preview was applied, or
  • the previous preview variant is still being shown.

This message remains in the patch controls instead of disappearing with the temporary progress overlay.

One active patch job

Patch/Alternative/Apply/Discard/variant controls are disabled while a patch job is active. A generation request also invalidates any stale patch request.

One-shot patch workers

A patch worker is terminated after every completed job. This releases the worker heap between Alternative clicks and prevents stale heavy-generation state from accumulating across previews.

Validation

STEP17_VALIDATION.mjs runs two consecutive interactive-style variants from the same committed world using the browser worker module.

Observed:

  • variant 0: 8.42 s, selected terrain variant 0
  • variant 1: 8.50 s, selected terrain variant 1
  • quality retry count: 0 for both
  • seam status: clean for both
  • elevation hashes: different
  • sea-mask hashes: different
  • administration hashes: different

Therefore the two Alternative requests produce materially different world data and exact requested variants.

All 8 existing test shards pass independently on the final Step 17 source with zero NG: assertions. All JavaScript/MJS files pass node --check.

Browser E2E note

The available container Chromium is subject to a localhost navigation policy/interstitial, so a reliable in-browser pointer/canvas E2E could not be completed here. Worker execution, variant data differences, cache-revision wiring, and all generator regressions are tested directly.