86 lines
4.9 KiB
Markdown
86 lines
4.9 KiB
Markdown
# 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.
|