Files

16 KiB

ExoPlaSim web UI

Objective and invariants

Build a usable scientific workbench from the maintained PHP web-app-starter. Remove demo content. Manage parameters, background runs, logs, and real spatial output.

Keep the Fortran simulator and checked build. PHP owns HTTP handling, queue management, and background-job control. Python programs are scientific executables called by PHP, not server implementations. Do not run simulation or result extraction in HTTP requests. Support relative filesystem paths. All application operations use ordinary query parameters through the PHP front controller. PHP reads $_GET and $_POST; do not parse URL locators or paths. Do not add custom servers, CGI endpoints, or a separate routing layer. Preserve truthful saves, immutable job inputs, cancellation, and outputs. Use one workspace with no accounts, sign-in, or logout. Keep runtime data outside the served source tree. Use starter shell utilities and components. Do not use application path routing. Do not add external services or automation.

Success criteria

  • The browser opens the single-user workspace directly. It creates, edits, clones, exports, and queues a parameter set.
  • An unprivileged worker runs the real simulator and survives request termination.
  • The browser shows queue state, progress, bounded logs, failures, cancellation, and retry.
  • Real output supports field, time, and level selection, map/globe rendering, charts, and downloads.
  • No accounts, sessions, CSRF checks, network gates, TLS requirements, or application-specific server configuration remain.
  • Setup, service files, tests, and current documentation ship in the project repository.
  • The user edits height, land mask, land roughness, and broadband land albedo; saved versions feed real runs through immutable captures.

Current state

Status: complete. Current source, runtime, browser checks, and repository delivery have been verified.

Source: project web/, web/server/, config/web.json, and scripts/. Runtime uses the host's ordinary PHP setup. The private checkout is outside the webroot. public_root contains only the PHP entry and browser assets. No application-specific nginx configuration, redirects, aliases, custom servers, or CGI endpoints are permitted.

The starter import is the clean maintained local commit 1a246ce4550a0b63dedaefbc62ef7946c4000b2d. Keep the maintained componentized shell and record provenance. The imported .git, logs, agent state, and code-search tools are excluded.

Goal tree

  • G1: A clean starter-derived application shell works.
    • G1.1: Import the maintained starter and record its source.
    • G1.2: Remove demos, unused themes/assets, and unused broker tooling.
    • G1.3: Preserve starter shell utilities and component dispatch. Do not use sessions or security gates in this private dev app.
  • G2: Scientific parameter sets are reproducible.
    • G2.1: Generate a parameter catalog from the installed Model signature and scientific docstrings.
    • G2.2: Save, clone, import, export, and validate parameter sets.
    • G2.3: Snapshot validated inputs into immutable jobs.
  • G3: Background jobs have reliable lifecycle management.
    • G3.1: PHP persists the queue in SQLite and claims jobs atomically.
    • G3.2: An unprivileged PHP worker calls the scientific executables with finite limits.
    • G3.3: Publish phase/progress/logs and support cancel, retry, and interrupted-run recovery.
  • G4: Model output is useful in the browser.
    • G4.1: Extract NPZ output into indexed binary fields and bounded statistics.
    • G4.2: Render real flat maps and interactive globes with time/level/field controls.
    • G4.3: Provide global-mean charts, data inspection, and downloads.
  • G6: The user can generate a random exoplanet.
    • G6.1: Use a saved seed so generation is repeatable.
    • G6.2: Generate a spherical elevation map and a matching land/ocean mask.
    • G6.3: Provide controls for land fraction, terrain relief, and geographic scale.
    • G6.4: Generate compatible planet, orbit, star, and atmosphere parameters. Keep them editable before a run.
    • G6.5: Preview the generated surface on a map and globe. Export its recipe and surface files.
    • G6.6: Convert the surface to ExoPlaSim inputs at the selected resolution. Test coordinate order and elevation-to-geopotential conversion.
  • G7: Editable surface maps feed real simulation inputs.
    • G7.1: Store immutable height, land-mask, roughness, and broadband albedo versions through PHP with real Gaussian grids.
    • G7.2: Provide geographic brushes, range limits, smoothing, undo, redo, keyboard access, and touch controls.
    • G7.3: Start from generated terrain or saved versions. Keep output fields separate from input maps.
    • G7.4: Snapshot map versions into each queued job. Verify retry and later edits cannot change those inputs.
    • G7.5: Run edited maps through the native model and verify SRA coordinates, gravity conversion, and actual model inputs.
  • G5: Deployment and acceptance are repeatable.
    • G5.1: Publish public-only assets and an ordinary PHP entry. Keep private source outside the webroot. Install the systemd worker without application-specific nginx configuration.
    • G5.2: Test queue concurrency, scientific validation, frame bounds, failures, and ordinary cookie-free saves.
    • G5.3: Complete a real browser-to-worker-to-visualization run.
    • G5.4: Test relative assets, query operations, APIs, and downloads through the existing PHP front controller. Do not add test servers or CGI mount schemes.
    • G5.5: Test relative storage paths and scientific commands from another working directory.
    • G5.6: Verify that PHP owns every server lifecycle operation. Remove Python server implementations.

Acceptance evidence

Requirement Evidence
Direct workspace, parameter CRUD, validation, truthful pending saves tests/web-http.php, tests/web-backend.php, tests/web-gui-workbench.js, tests/web-gui-numbers.py, and dated GUI acceptance
Immutable specs and native map captures, retry after changes and deletion Backend and worker tests, retained native inputs, four-map runs in docs/work/2026-10-10/web-acceptance.md
Independent worker, atomic claims, finite limits, cancellation and recovery tests/web-worker.php, systemd state, real native jobs, and installer lock tests
Native fields, units, times, levels, weighted means, bounds and downloads Python results tests, tests/web-api.php, native GUI frames and download checks
Reproducible planet generation and compatible native maps Python planet tests, generated and edited climate runs in dated acceptance
Brushes, smoothing, undo/redo, keyboard, touch, saved versions and failure recovery tests/web-map-brush.js, tests/web-gui-editor.js, and VM 101 mobile checks
RGB temperature/precipitation/elevation view tests/web-composite.js, tests/web-gui-composite.js, and docs/work/2026-10-10/rgb-output.md
Ordinary PHP query operations without security/session machinery Source audit, cookie-free live HTTP harness, and tests/web-public.php
Relative paths and repeatable installation without data replacement Worker/Python fixtures from another working directory, tests/web-installer.py, and docs/work/2026-10-11/final-ui.md
Repository delivery Private forge push and clean-checkout suites recorded in docs/work/2026-10-11/final-ui.md

Shared implementation contract

config/web.json is the shared configuration source. Consumers resolve relative storage keys against storage.root. Resolve the Python path against the project root. EXOPLASIM_CONFIG can select another configuration file. Do not paste host paths or operational limits into another definition.

A saved experiment contains id, owner, name, spec, created_at, and updated_at. IDs are 32 lowercase hexadecimal characters. A job snapshots an experiment's name and spec. Editing an experiment never edits an existing job.

A spec has this shape:

{"model":{"resolution":"T21","layers":10,"ncpus":1},"parameters":{},"run":{"cycles":1,"steps":1440}}

Only the constructor fields shown are public. Precision remains FP64. run.steps may be null for a full model year, or a bounded integer for an explicit cycle. Do not call a custom-length cycle a year in UI copy. The worker controls model name, source, paths, and executables. Parameters are Model.configure overrides, not a second source of defaults.

The main worker owns scripts/web/parameters.py with catalog(config) and validate_spec(spec, config). Validation returns {ok, spec, errors}. The cached catalog contains fields as an array of {name,label,type,default,nullable,description,group,editable,choices?}, plus model/run defaults and limits. Types are number, integer, boolean, string, object, or array. Derive defaults from the signature. Reject paths, scripts, raw namelist injection, and unknown fields. File-backed inputs need managed uploads before they become editable. Control runsteps through the run envelope. All runnable specs require spatial output.

The main worker also owns web/lib/parametercatalog.class.php, with ParameterCatalog::schema() and ParameterCatalog::validate($spec), using the same cached schema. Save validation and queue validation must report field errors rather than silently discard input.

PHP storage boundary

The PHP backend owns web/server/worker.php and web/config/lab.php, which exposes lab_config() with resolved keys database, jobs, runtime, runtime_lock, catalog, python, and project_root, while retaining other raw config values.

It owns web/server/schema.sql as the shared SQLite DDL, web/lib/labdb.class.php, web/lib/experiment.class.php, and web/lib/job.class.php. LabDb::connection() returns PDO. SQLite uses WAL, bounded busy waits, and indexes for ownership, state, and listing.

Methods return ordinary records or structured results {ok, data?, errors?, error?}. No application exceptions or request aborts for expected validation/not-found cases.

Experiment methods: all($owner), get($id,$owner), save($owner,$data), delete($id,$owner). Deletion affects the saved parameter set, not existing job snapshots.

Job methods: all($owner), get($id,$owner), enqueue($owner,$experiment), cancel($id,$owner), retry($id,$owner), log($id,$owner,$offset=0), and directory($job). Log reads are incremental and bounded. Listing is bounded. Retry creates a new job with the same immutable inputs. State names are queued, running, completed, failed, cancelled, and interrupted. A running cancellation sets cancel_requested; queued cancellation is immediate.

Jobs expose id, experiment_id, name, spec, status, phase, progress, completed_cycles, total_cycles, created_at, started_at, finished_at, updated_at, error, and cancel_requested. Timestamps use UTC ISO 8601. The worker owns execution PIDs and state transitions.

HTTP boundary

The PHP frontend owns query API operations under web/views/api/. It does not use CSRF checks. Use the existing PHP front controller with query parameters, for example ?api=frame&id=…&time=…. Do not parse route locators or request paths.

Responses are {ok:true,data:...} or {ok:false,error:...,errors?:...}. GET operation names are schema, experiments, jobs, log, results, series, frame, and download. Detail requests use id.

POST ?api=experiments saves {id?,name,spec}. POST ?api=experiment_delete deletes a saved set. POST ?api=jobs queues {experiment_id} after successful save. POST ?api=cancel and ?api=retry take {id}. The UI can clone or import through normal experiment save. Downloads and exports use only owned IDs and approved artifact identifiers.

The application is single-user. It has no accounts, sign-in, or logout. API mutations do not require sessions, CSRF tokens, or network checks. The workbench root carries a bootstrap object window.EXOPLASIM with api mapping operation names to relative query strings. config.workspace identifies the one workspace in storage. Do not add security gates or sessions to this private dev toy. The UI must show request errors and preserve edits.

Results boundary

The visualization implementation is scripts/web/results.py with prepare_results(npz_path, destination, dataset_id) and a CLI entry point. The worker calls it after each cycle.

Each job uses artifacts/datasets/<dataset_id>/. A dataset stores index.json with id, lat, lon, time, time_unit, levels, and fields. Each field is {name,label,unit,shape:[time,level,lat,lon],min,max}. Coordinate variables are not fields. Metadata labels and units come from ExoPlaSim NPZ metadata, not an invented registry.

Each field has <name>.f32 in little-endian C order and <name>.json with {mean,min,max} arrays shaped [time][level]. Global means use area weights and ignore nonfinite cells. Do not include large per-field statistics in the dataset index.

artifacts/index.json lists datasets as {id,label} and identifies latest. The PHP worker maintains this job index after the scientific child prepares each dataset. Publish indexes atomically after files are ready. Keep memory and storage bounded by config limits. Preserve NPZ, exported config, logs, and restart files for downloads.

GET ?api=results&id=...&dataset=... returns the selected dataset index plus datasets and latest. GET ?api=series selects id, dataset, field, and level, returning {time,time_unit,mean,min,max,unit}. GET ?api=frame selects those plus time and returns one binary float32 spatial frame. Bounds and file names come from the owned manifest. No Python process or full field-file read in a PHP request.

The visualization delegate owns web/js/visualization.js. Expose window.ExoVisualization with constructor (container) and methods setDataset(index, frameUrlFunction, seriesUrlFunction, options?), destroy(). options.gravity supplies the saved job's gravity for the RGB elevation channel. It creates its own field/time/level controls, map/globe, legend, inspector, and chart inside that container. URL callbacks take (field,time,level) and (field,level). It must handle aborts, stale responses, resize, no WebGL, and missing values. Use local native browser APIs, no CDN or new package installation.

The frontend delegate owns the workbench component, index view, workbench JS, and the ExoPlaSim theme. Render through component() / component_call(). Use one clear workspace with experiment selection, parameter editing, jobs, visualization, and logs. No demo data, marketing cards, planning explanations, or unnecessary subheadings.

Next

The accepted UI scope is complete. Earlier evidence is in docs/work/2026-10-10/web-acceptance.md. RGB evidence is in docs/work/2026-10-10/rgb-output.md. Final suites, screenshots, installation, and delivery are in docs/work/2026-10-11/final-ui.md.

Remaining scope and risks

Random exoplanet generation is part of the requested scope. Generated surfaces must reach the simulator, not remain decorative previews. Describe them as procedural scenarios, not reconstructed planets or geological predictions.

Managed height, land-mask, roughness, and broadband land-albedo maps are part of the active scope. Restart-from-UI, parameter sweeps, SBDART pipelines, comparative climate analysis, and administrator storage cleanup may need later increments. Do not expose inactive controls or claim these work. Large models can exceed resource limits. Native settings and complete MPI acceptance remain outside this UI slice.