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

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.