mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
* fix(forecasts): unwrap seed-contract envelope in canonical-key sim patcher Production bug observed 2026-04-23 across both forecast worker services (seed-forecasts-simulation + seed-forecasts-deep): every successful run logs `[SimulationDecorations] Cannot patch canonical key — predictions missing or not an array` and silently fails to write simulation adjustments back to forecast:predictions:v2. Root cause: PR #3097 (seed-contract envelope dual-write) wraps canonical seed writes in `{_seed: {...}, data: {predictions: [...]}}` via runSeed. The Lua patcher (_SIM_PATCH_LUA) and its JS test-path mirror both read `payload.predictions` directly with no envelope unwrap, so they always return 'MISSING' against the new shape — meeting the documented pattern in the project's worldmonitor-seed-envelope-consumer-drift learning (91 producers enveloped, private-helper consumers not migrated). User-visible impact: ForecastPanel renders simulation-adjusted scores only when a fast-path seed has touched a forecast since the bug landed; deep-forecast and simulation re-scores never reach the canonical feed. Fix: - _SIM_PATCH_LUA detects envelope shape (`type(payload._seed) == 'table' and type(payload.data) == 'table'`), reads `inner.predictions`, and re-encodes preserving the wrapper so envelope shape persists across patches. Legacy bare values still pass through unchanged. - JS test path mirrors the same unwrap/rewrap. - New test WD-20b locks the regression: enveloped store fixture, asserts `_seed` wrapper preserved on write + inner predictions patched. Also resolves the per-run `[seed-contract] forecast:predictions missing fields: sourceVersion — required in PR 3` warning by passing `sourceVersion: 'detectors+llm-pipeline'` to runSeed (PR 3 of the seed-contract migration will start enforcing this; cheap to fix now). Verified: typecheck (both tsconfigs) clean; lint 0 errors; test:data 6631/6631 green (forecast suite 309/309 incl new WD-20b); edge-functions 176/176 green; markdown + version-check clean. * fix(forecasts): tighten JS envelope guard to match Lua's strict table check PR #3348 review (P2): JS test path used `!!published._seed` (any truthy value) while the Lua script requires `type(payload._seed) == 'table'` (strict object check). Asymmetry: a fixture with `_seed: true`, `_seed: 1`, or `_seed: 'string'` would be treated as enveloped by JS and bare by Lua — meaning the JS test mirror could silently miss real Lua regressions that bisect on fixture shape, defeating the purpose of having a parity test path. Tighten JS to require both `_seed` and `data` be plain objects (rejecting truthy non-objects + arrays), matching Lua's `type() == 'table'` semantics exactly. New test WD-20c locks the parity: fixture with non-table `_seed` (string) + bare-shape `predictions` → must succeed via bare path, identical to what Lua would do. Verified: 6632/6632 tests pass; new WD-20c green.
774 KiB
774 KiB