@@ -12,7 +12,7 @@ import {
1212import * as registry from './domain/registry.js' ;
1313import { load as loadDomain } from './domain/loader.js' ;
1414import { indexQuestions , getAvailableQuestions } from './domain/questions.js' ;
15- import { Estimator , DEFAULT_LENGTH_SCALE } from './learning/estimator.js' ;
15+ import { Estimator } from './learning/estimator.js' ;
1616import { Sampler } from './learning/sampler.js' ;
1717import { getCentrality } from './learning/curriculum.js' ;
1818import { Renderer } from './viz/renderer.js' ;
@@ -29,24 +29,11 @@ import { announce, setupKeyboardNav } from './utils/accessibility.js';
2929const GLOBAL_REGION = { x_min : 0 , x_max : 1 , y_min : 0 , y_max : 1 } ;
3030const GLOBAL_GRID_SIZE = 50 ;
3131
32- function lengthScaleForDomain ( domain ) {
33- if ( ! domain ) return DEFAULT_LENGTH_SCALE ;
34- if ( domain . level === 'all' ) return DEFAULT_LENGTH_SCALE * 2 ;
35- if ( domain . level === 'sub' ) return DEFAULT_LENGTH_SCALE * 0.5 ;
36- return DEFAULT_LENGTH_SCALE ; // general
37- }
38-
39- function lengthScaleForDomainId ( domainId ) {
40- const domain = registry . getDomain ( domainId ) ;
41- return lengthScaleForDomain ( domain ) ;
42- }
43-
44- function enrichResponsesWithLengthScale ( responses ) {
45- return responses . map ( r => {
46- if ( r . lengthScale != null ) return r ;
47- return { ...r , lengthScale : lengthScaleForDomainId ( r . domain_id ) } ;
48- } ) ;
49- }
32+ // Uniform length scale for all observations — no per-domain variation.
33+ // Previously sub-domains used 0.075 and "all" used 0.30, which created jagged,
34+ // inconsistent smoothness. A single scale of 0.18 produces natural gradients
35+ // while preserving spatial structure in the Matérn 3/2 kernel.
36+ const UNIFORM_LENGTH_SCALE = 0.18 ;
5037
5138let renderer = null ;
5239let minimap = null ;
@@ -321,13 +308,31 @@ async function switchDomain(domainId) {
321308 estimator . init ( domainGrid , domainRegion ) ;
322309 sampler . configure ( domainGrid , domainRegion ) ;
323310
324- const allResponses = enrichResponsesWithLengthScale ( $responses . get ( ) ) ;
311+ // Enrich any responses missing x/y from the freshly-loaded question index.
312+ // This handles older exports that lacked coordinates.
313+ let allResponses = $responses . get ( ) ;
314+ let enriched = 0 ;
315+ const patched = allResponses . map ( r => {
316+ if ( r . x != null && r . y != null ) return r ;
317+ const q = questionIndex . get ( r . question_id ) ;
318+ if ( q && q . x != null && q . y != null ) {
319+ enriched ++ ;
320+ return { ...r , x : q . x , y : q . y } ;
321+ }
322+ return r ;
323+ } ) ;
324+ if ( enriched > 0 ) {
325+ console . log ( `[app] Enriched ${ enriched } responses with x/y from question index` ) ;
326+ $responses . set ( patched ) ;
327+ allResponses = patched ;
328+ }
329+
325330 const relevantResponses = allResponses . filter (
326331 ( r ) => r . x != null && r . y != null
327332 ) ;
328333 if ( relevantResponses . length > 0 ) {
329- estimator . restore ( relevantResponses ) ;
330- globalEstimator . restore ( relevantResponses ) ;
334+ estimator . restore ( relevantResponses , UNIFORM_LENGTH_SCALE ) ;
335+ globalEstimator . restore ( relevantResponses , UNIFORM_LENGTH_SCALE ) ;
331336 }
332337
333338 const estimates = estimator . predict ( ) ;
@@ -413,9 +418,6 @@ function handleAnswer(selectedKey, question) {
413418
414419 const isCorrect = selectedKey === question . correct_answer ;
415420
416- const questionDomainId = ( question . domain_ids || [ ] ) . find ( id => id !== 'all' ) || currentDomainBundle . domain . id ;
417- const ls = lengthScaleForDomainId ( questionDomainId ) ;
418-
419421 const response = {
420422 question_id : question . id ,
421423 domain_id : currentDomainBundle . domain . id ,
@@ -424,16 +426,15 @@ function handleAnswer(selectedKey, question) {
424426 timestamp : Date . now ( ) ,
425427 x : question . x ,
426428 y : question . y ,
427- lengthScale : ls ,
428429 } ;
429430
430431 const current = $responses . get ( ) ;
431432 const filtered = current . filter ( r => r . question_id !== question . id ) ;
432433 const isReanswer = filtered . length < current . length ;
433434 $responses . set ( [ ...filtered , response ] ) ;
434435
435- estimator . observe ( question . x , question . y , isCorrect , ls ) ;
436- globalEstimator . observe ( question . x , question . y , isCorrect , ls ) ;
436+ estimator . observe ( question . x , question . y , isCorrect , UNIFORM_LENGTH_SCALE ) ;
437+ globalEstimator . observe ( question . x , question . y , isCorrect , UNIFORM_LENGTH_SCALE ) ;
437438 const estimates = estimator . predict ( ) ;
438439 $estimates . set ( estimates ) ;
439440
@@ -547,10 +548,9 @@ function handleImport(data) {
547548 $responses . set ( merged ) ;
548549
549550 if ( estimator ) {
550- const enriched = enrichResponsesWithLengthScale ( merged ) ;
551- const relevant = enriched . filter ( r => r . x != null && r . y != null ) ;
552- estimator . restore ( relevant ) ;
553- if ( globalEstimator ) globalEstimator . restore ( relevant ) ;
551+ const relevant = merged . filter ( r => r . x != null && r . y != null ) ;
552+ estimator . restore ( relevant , UNIFORM_LENGTH_SCALE ) ;
553+ if ( globalEstimator ) globalEstimator . restore ( relevant , UNIFORM_LENGTH_SCALE ) ;
554554 const estimates = estimator . predict ( ) ;
555555 $estimates . set ( estimates ) ;
556556
@@ -566,6 +566,13 @@ function handleImport(data) {
566566 announce ( msg ) ;
567567 _showBanner ( msg , 'success' ) ;
568568 console . log ( '[import]' , msg ) ;
569+
570+ // If we're still on the welcome screen, switch to map view with "all" domain.
571+ // switchDomain will re-restore the GP from $responses (now including imports).
572+ if ( ! currentDomainBundle ) {
573+ controls . setSelectedDomain ( 'all' ) ;
574+ $activeDomain . set ( 'all' ) ;
575+ }
569576}
570577
571578function handleViewportChange ( viewport ) {
0 commit comments