22 KiB
Time-Series SBAS And SARscape Integration Design
1. Problem Statement
The current time-series route can find and run a scene stack, but the system does not yet treat SBAS as a first-class production input. The main gaps are:
find-ps-timeseriesreturns scenes, not a durable SBAS network.PsTaskBatchis used as a production input even though it is a thin list of paths.- Planning context is partly duplicated in
PsTaskItem.remark. copy-ps-stackcopies source folders, but does not create a stack-level production package.- The managed time-series runner reconstructs input state at run time.
- SARscape is currently integrated only as a D-InSAR pair processor.
The design goal is to make one immutable stack manifest the source of truth for every SBAS run, then let ISCE2/MintPy and SARscape consume the same contract.
2. Target Workflow
AOI + filters
-> time-series stack search
-> SBAS network plan
-> user review and commit
-> immutable stack package
-> processor workflow
-> publish bundle
-> psinsar catalog
The stack plan and the production package are separate states. A plan is a previewable proposal; a package is a committed production input.
3. Planning Contract
3.1 Search API
Add or evolve the current find-ps-timeseries route toward:
POST /timeseries/plans/search
Core request fields:
- AOI source: uploaded shapefile, region geometry, or GeoJSON.
- Scene compatibility filters: satellite, orbit direction, imaging mode, polarization, date range.
- Scene thresholds:
initial_overlap_threshold,final_overlap_threshold. - Network thresholds:
time_baseline_min,time_baseline_max,spatial_baseline_max_meters, laterperpendicular_baseline_max_meters. - Network policy:
strategy,num_connections,reference_image_id. - Processor hint: optional
processor_target, for exampleisce2_stack_mintpyorsarscape_sbas.
3.2 Plan Tables
Existing:
timeseries_stack_planstimeseries_stack_plan_items
New:
timeseries_stack_plan_edges
The edge table stores the selected SBAS graph:
- plan reference
- master/slave plan item references
- master/slave radar scene references
- optional
pairing_metric_cachereference - temporal baseline
- spatial/perpendicular baseline
- scene overlap ratio
- AOI pair overlap ratio
- selection reason and score
- enabled flag
This lets the system answer: which pairs were selected, why were they selected, and what graph was actually submitted.
4. Production Input Package
Committed production input is represented by a prepared stack manifest. In the current backend this file is:
backend/runtime/timeseries_work/<run_id>/input/selected_stack_manifest.json
This file is not the same thing as a TimeseriesStackPlan. The plan is the
candidate pool and audit graph. The prepared stack is the smaller frozen set
submitted to a processor.
Schema:
{
"schema": "insar.timeseries-stack/v1",
"prepared_stack_schema": "insar.prepared-sbas-stack/v1",
"manifest_role": "prepared_sbas_stack",
"mode": "sbas",
"plan_id": "tsp_...",
"prepared_stack_id": "pss_...",
"source_plan_id": "tsp_...",
"source_batch_id": "...",
"processor_code": "sarscape_sbas",
"aoi": {},
"candidate_pool_source": {},
"selection_params": {},
"scenes": [],
"network_edges": [],
"reference_date": "YYYYMMDD",
"production_contract": {
"input_policy": "prepared_stack_only",
"catalog_scan_allowed_after_prepare": false,
"scene_selection_frozen": true
},
"artifacts": {
"selected_network_edges_path_windows": "..."
},
"prepared_stack_validation": {},
"prepared_at_utc": "...",
"manifest_checksum": "..."
}
Rules:
- A production run consumes the prepared manifest, not
PsTaskItem.remarkand not a fresh scan of the full radar catalog. - The manifest is immutable after
preparecompletes, except for explicit retry/re-prepare workflows. - Processor-specific materialization is recorded in a separate processor manifest.
- Source data copying must include the manifest and graph.
4.1 Layered SBAS Input Model
The production model is now four layers:
-
Full radar inventory
- The long-lived scene catalog and pairing metric cache.
- It can be large and dirty/rebuilt over time.
-
Candidate time-series pool
TimeseriesStackPlanORM, plan items, and plan edges.- This is the large pool selected by AOI, date, orbit, baseline, overlap, and network policy.
- It records why each scene and edge was selected.
-
Prepared SBAS stack
selected_stack_manifest.jsonwithprepared_stack_schema=insar.prepared-sbas-stack/v1.- Contains only the frozen scenes for this run.
- Writes
input/selected_network_edges.jsonas a standalone artifact. - Records validation results for scene files, graph count/date consistency, DEM availability when required, and the no-catalog-scan production policy.
-
Processor execution
- SARscape
wf_sbasconsumes the prepared scene stack. - System
network_edgesare mandatory as the planning/audit graph, but the nativewf_sbaspath may rebuild the executable graph internally. - When SARscape's actual graph can be extracted, it should be saved as
actual_network_edges.jsonand compared withselected_network_edges.json.
- SARscape
Backend enforcement:
prepare_run()creates the prepared stack contract and validates it.build_sarscape_processor_preflight()refuses non-prepared manifests.run_sarscape_sbas()refuses non-prepared manifests and missingselected_network_edges.json.execute_template_workflow()in the SARscape service has a second guard so lower-level execution cannot accidentally run from a candidate pool.
5. Processor Boundary
Introduce a time-series processor interface:
TimeseriesProcessor
check_available()
preflight(manifest)
build_workflow(run)
prepare_inputs(run)
execute_step(run, step_id)
export_publish_bundle(run)
Processor codes:
isce2_stack_mintpysarscape_sbas
The existing timeseries_service can remain the orchestration service, but processor-specific logic should move behind this interface.
6. SARscape SBAS Processor
SARscape SBAS should be a stack-level processor, not an extension of the D-InSAR pair engine.
Suggested steps:
-
sarscape_preflight- Check ENVI, SARscape, taskengine, license, DEM, orbit pool, and output roots.
- Enumerate available SARscape SBAS/E-SBAS task names via
envipyengine.
-
sarscape_import- Import LT-1 scenes.
- Write
sarscape_import_manifest.json.
-
sarscape_connection_graph- Prefer the system-selected
network_edges. - If SARscape internally rebuilds the graph, export the actual graph as
actual_network_edges.json.
- Prefer the system-selected
-
sarscape_interferogram_generation -
sarscape_inversion- Generate time-series, velocity, coherence, and quality products.
-
sarscape_geocode_export -
export_publish_bundle -
register_psinsar_product
7. Result Contract
One SBAS run registers one psinsar product bundle.
Required bundle roles:
- stack manifest
- processor manifest
- selected network edges
- actual network edges if processor modified them
- velocity product
- time-series product
- temporal coherence or equivalent quality product
- geocoded rasters
- quicklooks
- logs
- processor reports
- product manifest
The catalog registers the publish manifest, not the transient work directory.
8. Delivery Phases
Phase 1: Planning Boundary
- Stop auto-creating PS batches after search.
- Persist
TimeseriesStackPlanEdge. - Return edges from
/timeseries-plans/{plan_id}. - Add network thresholds to
PsRequestwith backward-compatible defaults.
Phase 2: Manifest Boundary
- Add committed stack package creation.
- Generate immutable
stack_manifest.json. - Make the existing ISCE2/MintPy route consume the manifest.
Phase 3: SARscape Discovery
- Add a SARscape SBAS task verifier script.
- Capture task names and required parameters per installed SARscape version.
- Add
sarscape_sbaspreflight endpoint.
Initial implementation points:
scripts/verify_sarscape_sbas_tasks.pyPOST /idl/inspect/sarscape-sbasPOST /timeseries-production/sarscape-sbas/preflightpython -m backend.app.services.envi_runner_cli --inspect-sarscape-sbas
These entry points must stay read-only. They instantiate ENVI task definitions and inspect parameters, but do not execute SBAS processing.
The time-series SARscape preflight endpoint builds a processor manifest from
the committed PS batch/stack plan context. It reports the selected network
edges, the SARscape task sequence, required publish roles, and current blockers.
At this phase it must return ready_for_pipeline_design=true when ENVI/SARscape
is discoverable, but ready_for_execution=false until a checked-in parameter
template and job handler are implemented.
Current implementation status:
sarscape_sbasis a selectable time-series processor.- The production UI defaults to
ENVI/SARscape SBASwithPreflight only. POST /timeseries-production/runsacceptsprocessor_codeandexecution_mode.- SARscape runs use workflow
psinsar_sarscape_sbas_chain. - Preflight-only SARscape runs execute
prepareplussarscape_processor_preflight, then complete the task without launching the long SARscape stack execution. - Full execution is gated by
SARSCAPE_SBAS_ALLOW_EXECUTION=trueand avalidated=trueparameter template atSARSCAPE_SBAS_PARAMETER_TEMPLATE_PATH. - The checked-in template at
backend/templates/sarscape_sbas_parameter_template.example.jsonis a placeholder contract and is intentionally not executable.
Observed on the target workstation:
- Lightweight
Engine.tasks()discovery succeeds. - Static
.taskextraction succeeds without starting taskengine. The extractor is:scripts/extract_sarscape_sbas_task_templates.py
- The installed SARscape exposes native workflow metatasks:
wf_sbaswf_esbas
wf_sbasis an ENVI metatask atC:\Program Files\Harris\ENVI56\user_custom_code\wf_sbas.task. It is not listed byEngine.tasks()on this workstation, butEngine("ENVI").task("wf_sbas")can instantiate it successfully. Discovery therefore combinesEngine.tasks()with static.taskfile detection. It contains an embedded 11-node DAG:SARscape_setting_output_foldersSARsLoadPreferencesSARsImportSarSelectorENVIEXTRACTELEMENTSFROMARRAYTASKSARscapeSuggestLooksSARsInSARStackSBASGenerateConnectionGraphSARsInSARStackSBASInterferogramGenerationSARsInSARStackSBASInversionStep1SARsInSARStackSBASInversionStep2SARsInSARStackSBASGeocodeSARscapeEnviuriToShape
- The static
wf_sbas.taskfile contains 18 parameter entries including the embeddedDAGdefault. Live taskengineQueryTaskexposes 17 callable parameters; it does not require the caller to passDAG. - The core production inputs are:
INPUT_FILE_LISTSARSCAPE_PREFERENCEDEM_SARSCAPEDATAOUTPUT_FOLDERGEOCODE_RG_GRID_SIZEESTIMATE_RESIDUAL_HEIGHTDISPLACEMENT_MODEL_TYPEOUTPUT_ENVI_CARTOGRAPHIC_SYSTEM
wf_sbasreturns SBAS product handles:DISPLACEMENT_SARSCAPEDATADEM_OUT_SARSCAPEDATACORRECTION_H_SARSCAPEDATACOHERENCE_SARSCAPEDATAALOS_SARSCAPEDATAILOS_SARSCAPEDATAVELOCITY_SARSCAPEDATAOUTPUT_SHAPES
- The installed SARscape also exposes these stack tasks:
SARsInSARStackSBASGenerateConnectionGraphSARsInSARStackSBASInterferogramGenerationSARsInSARStackSBASInversionStep1SARsInSARStackSBASInversionStep2SARsInSARStackSBASGeocodeSARsInSARStackSBASVariogramSARsInSARStackESBASInterferogramGenerationSARsInSARStackESBASInversionSARsInSARStackESBASGeocodeSARsInSARConnectionGraphESBAS
- Reading
.parametersfor stack SBAS tasks can hang taskengine. Parameter discovery must therefore be optional, subprocess-isolated, and timeout-bound. Processor implementation should use a checked-in task template or SARscape help/SML-derived parameter contract rather than relying on live parameter introspection at run time. - Timeout cleanup must remove only taskengine processes spawned by the timed-out inspection subprocess. Existing user-launched ENVI/taskengine sessions should not be killed by name.
- SARscape/taskengine can create zero-byte
env_*.xyzandIDL*.tmpfiles in the process current working directory. ENVI runner cwd and temp variables must point atbackend/runtime/idl_worker/envi_cwd, not the repository root. Root-levelenv_*.xyzandIDL*.tmpare disposable taskengine leftovers.
Phase 3.5: SARscape Native Workflow Strategy
The short-term production strategy is to integrate SARscape through wf_sbas.
This is the lowest-risk ENVI/SARscape path because SARscape already wires import,
connection graph generation, interferogram generation, inversion, geocoding, and
shape export in one metatask DAG.
The backend template contract now supports two execution strategies:
-
native_workflow_metatask- Preferred first implementation.
- Executes
wf_sbasonce with the committed stack manifest converted intoINPUT_FILE_LIST, configured DEM, output folder, and basic SBAS options. - Does not directly consume the system-selected
network_edges. - Requires post-run extraction of SARscape's actual connection graph for audit.
-
explicit_stack_tasks- Future controllable implementation.
- Executes
SARsInSARStackSBASGenerateConnectionGraph,InterferogramGeneration,InversionStep1,InversionStep2, andGeocodeas separate tasks. - May allow tighter control of graph settings, but direct injection of the system-selected edge list is not verified yet.
Current rule:
network_edgesremain mandatory in the stack manifest because they are the system planning decision and task-dispatch audit record.- When using
wf_sbas, SARscape may rebuild the graph internally. The output bundle must therefore contain both:selected_network_edges.jsonactual_network_edges.json, when it can be extracted from SARscape outputs
Current code points:
backend/app/services/envi_service.py- Discovers
wf_sbas,wf_esbas, support tasks, and stack tasks. - Cleans up only newly spawned
taskengine.exePIDs on timeout. - Runs subprocess and in-process envipyengine calls from
backend/runtime/idl_worker/envi_cwdso taskengine temp files do not pollute the project root.
- Discovers
backend/app/services/sarscape_sbas_service.py- Builds processor manifests with
execution_strategy. - Reports both native and explicit strategy availability.
- Requires
insar.prepared-sbas-stack/v1before execution. - Executes
native_workflow_metataskonly when the template is validated and execution is explicitly enabled.
- Builds processor manifests with
backend/app/services/timeseries_service.py- Treats
TimeseriesStackPlanas the candidate pool. - Creates
selected_stack_manifest.jsonas the prepared stack inprepare_run(). - Writes
input/selected_network_edges.jsonbefore SARscape preflight or execution. - Refuses SARscape preflight/execution when the prepared stack validation fails.
- Treats
backend/templates/sarscape_sbas_parameter_template.example.json- Records the
wf_sbasparameter contract and DAG summary. - Keeps
validated=falseuntil a controlled run validates parameters and output capture.
- Records the
scripts/extract_sarscape_sbas_task_templates.py- Regenerates the static parameter report from installed
.taskfiles.
- Regenerates the static parameter report from installed
Open engineering items:
- Confirm
wf_sbas.INPUT_FILE_LISTaccepts the same LT-1*.meta.xmllist used by current SARscape import tasks. - Confirm whether
DAGmust be passed explicitly or SARscape uses the embedded default fromwf_sbas.task. - Locate SARscape's written connection graph or auxiliary processing file and
convert it into
actual_network_edges.json. - Map
VELOCITY_SARSCAPEDATA,DISPLACEMENT_SARSCAPEDATA,COHERENCE_SARSCAPEDATA, andOUTPUT_SHAPESinto the unifiedpsinsarpublish bundle. - Decide later whether to invest in
explicit_stack_tasksfor strict graph injection, depending on whether SARscape exposes a supported graph import or connection-list parameter.
Smoke test on 2026-04-30:
- Applied the non-destructive
008_timeseries_stack_plan_edges.sqlmigration. - Backfilled two edges for test plan
tsp_d89bfc5bded744e6bf9b60c1frompairing_metric_cachebecause the plan was created before the edge table existed. - Ran SARscape SBAS preflight for batch
e240a63a-5941-4a86-8aae-182a6bc95dae. - Result:
scene_count=3network_edge_count=2ready_for_pipeline_design=trueready_for_execution=falseexecution_strategy=native_workflow_metataskmissing_required_tasks=[]- blockers are only
Template is not marked validated=trueandSARSCAPE_SBAS_ALLOW_EXECUTION is false.
- Created a
preflight_onlyrunb7c2df45-a891-4ff7-b106-013e8d285fbdand executed itsprepareplussarscape_processor_preflightsteps. This wroteselected_stack_manifest.jsonandsarscape_sbas_processor_manifest.jsonwithout launching the full SARscape SBAS pipeline. - Dispatch verification for workflow
eeaf1d82-7268-490c-9fb5-911a00a475c6exposed a real workflow bug:workflow_service.mark_step_completed()advanced downstream steps toREADY, but the database session hasautoflush=False, so the immediateenqueue_ready_steps()query did not see the newREADYstatus.sarscape_processor_preflighttherefore stayedREADYwithout a job. - Fixed the dispatcher by flushing after
_advance_ready_steps()and beforeenqueue_ready_steps(). - Verified the dispatcher fix in a rollback-only two-step workflow regression
check: completing step
aimmediately advanced stepbtoRUNNINGand created its queued job. - Re-ran the controlled dispatch path for only this workflow:
TIMESERIES_PREPARE:COMPLETEDTIMESERIES_SARSCAPE_PREFLIGHT:COMPLETED- workflow status:
COMPLETED - task status:
COMPLETED, progress100 - run status:
PREPARED - no
TIMESERIES_RUN_SARSCAPE_SBASjob orrun_sarscape_sbasstep was created because execution mode waspreflight_only.
- Root-level taskengine leftovers after the run:
env_*.xyz:0IDL*.tmp:0ENVI status now reports runner cwd asbackend/runtime/idl_worker/envi_cwd.
Parameter template validation on 2026-04-30:
- Initial live
Engine("ENVI").task("wf_sbas")parameter inspection failed withENVITASK: No task matches: wf_sbas, even though the staticwf_sbas.taskfile was present. - Root cause: SARscape installed
wf_sbas.taskunderC:\Program Files\Harris\ENVI56\user_custom_code, while taskengine only auto-loads deployed custom tasks fromENVI_CUSTOM_CODE, the ENVIcustom_codedirectory, the application user directory, or IDL packages. - Backend runner now sets
ENVI_CUSTOM_CODEto the discovered SARscapeuser_custom_codedirectory. This is process-local to the runner and does not modify the machine-level environment. - After the fix, live
wf_sbasparameter inspection succeeds:available=trueparameter_count=17- required inputs:
INPUT_FILE_LIST - outputs:
OUTPUT_SHAPES,DISPLACEMENT_SARSCAPEDATA,DEM_OUT_SARSCAPEDATA,CORRECTION_H_SARSCAPEDATA,COHERENCE_SARSCAPEDATA,ALOS_SARSCAPEDATA,ILOS_SARSCAPEDATA,VELOCITY_SARSCAPEDATA
- Added repeatable validation script:
scripts/validate_sarscape_sbas_template.py. - Validation report:
backend/runtime/sarscape_sbas_template_validation_latest.json. - Current 3-scene validation result:
ok=true- validation scope: template contract only, no
task.execute() - manifest scene count:
3 - network edge count:
2 INPUT_FILE_LIST_count=3- scene
meta_path,tiff_path, and folders all exist - DEM base,
.sml, and.hdrall exist - remaining execution gate issue: checked-in template is still
validated=false
Prepared stack boundary implementation on 2026-04-30:
- Added
prepared_stack_schema=insar.prepared-sbas-stack/v1toselected_stack_manifest.json. - Added
prepared_stack_id,source_plan_id,source_batch_id,candidate_pool_source, andproduction_contract. - Added
input/selected_network_edges.jsonas the frozen planning/audit graph artifact. - Added prepared stack validation for:
- scene count and dates
- required scene folder, TIFF, and metadata XML paths
- zero-size source files
- network edge count and edge date consistency
- SARscape DEM dependency when SARscape is the selected processor
- missing
selected_network_edges.json
- SARscape processor preflight and execution now reject manifests that are not prepared stacks. The lower-level SARscape executor repeats this guard before calling any ENVI task.
Prepared stack UI/API update on 2026-04-30:
- Added read-only backend summary endpoint:
GET /timeseries-production/runs/{run_id}/prepared-stack. - The endpoint reads only existing run artifacts and does not trigger catalog scans, preflight, or SARscape execution.
- The summary reports:
- prepared stack state
prepared_stack_id- manifest and selected network edge artifact paths
- scene count and network edge count
- prepared stack validation result
- SARscape processor manifest readiness and blockers
TimeseriesProductionPanelnow shows a dedicatedPrepared SBAS Stacksection in run details.- The SARscape preflight card now states that batch preflight is against the candidate pool, while production freezes a prepared stack before processor execution.
usePairingLogicnow marks created PS batches as candidate time-series pools in the planning context and logs that production will freeze a prepared SBAS stack duringprepare.
Phase 4: SARscape Execution
- Implement the SARscape SBAS processor steps.
- Serialize taskengine execution through the existing ENVI lock.
- Persist step manifests and logs.
Initial execution skeleton is in place:
TIMESERIES_SARSCAPE_PREFLIGHTTIMESERIES_RUN_SARSCAPE_SBASbackend/app/services/sarscape_sbas_service.py
The execution handler resolves template macros and calls execute_envi_task
only after the template is readable, structurally valid, marked
validated=true, required tasks are discoverable, and execution is explicitly
enabled.
Phase 5: Unified Result Management
- Normalize ISCE2/MintPy and SARscape outputs into the same publish bundle roles.
- Keep processor-specific files as secondary assets.
- Show products by role in the UI, not by processor-specific filenames.