PSS SINCAL
SINCAL is one native project format capable of holding both balanced and
conductor-resolved networks. Select the electrical profile explicitly. The
current balanced reader produces the existing BalancedNetwork; it does not
infer balance from equal phase values or automatically reduce unbalanced data.
The explicit multiconductor profile produces MulticonductorNetwork through
powerio-tnd; neither profile silently retries the other family.
Build feature
Both readers, the byte-exact native echo and the experimental writer are the
sincal cargo feature of powerio-tnd, enabled by default by powerio, so the CLI, the Python wheel, the C ABI and the browser converter
include them. The feature brings in SQLite through powerio-tnd, which a
wasm32-unknown-unknown build compiles only with a C compiler that has a
WebAssembly backend. A facade built with default-features = false needs no C
compiler: grid_formats lists no SINCAL format, ParseOptions and
EmitOptions have no SINCAL field, and a SINCAL source or target fails with
REQUEST.SINCAL.FEATURE_DISABLED (REQUEST.DIST_FORMAT.SINCAL_FEATURE_DISABLED
from powerio-dist used directly). resolve_format still describes the
tokens, because format metadata is not a build probe.
Balanced reader
The sincal-balanced input token selects positive-sequence load flow. The
current profile accepts native SQLite schemas 14.8, 15.5 and 16.0 and .sinx archives,
with one base variant. Rust also accepts explicitly acquired schema-11.5 Access
records and selected absolute daily snapshots, as described below. It covers
buses, positive-sequence lines, static loads,
external sources, converter injections and two-winding transformers with fixed
common taps, plus fixed capacitor banks. Ideal external sources support absolute
and relative source/terminal voltage prescriptions and voltage-only limits.
Open terminals and inactive equipment remain in the network.
Unknown required modes fail with table, native record ID and field context.
let options = powerio::ParseOptions::default().format("sincal-balanced")?;
let module = powerio::parse_with_options("case.sinx", &options)?;
assert!(matches!(module.value(), powerio::PioValue::BalancedNetwork(_)));
powerio::emit(&module, "matpower", "case.m")?;
Ok::<(), Box<dyn std::error::Error>>(())
powerio summary case.sinx --from sincal-balanced
powerio convert case.sinx --from sincal-balanced --to matpower -o case.m
powerio serialize case.sinx --from sincal-balanced -o case.pio.json
Python uses powerio.parse(path, format="sincal-balanced"). The C ABI uses the
existing pio_parse format argument and pio_value_balanced_network typed
accessor. No new network type or binding ABI is introduced.
Bare sincal and an undeclared .sinx require profile selection. Explicit
selection does not authorize discarding incompatible phase-resolved data:
unsupported terminal or load modes are errors, with no fallback to another
family. The native model’s source-format identity is sincal; the retained
source records the selected input profile as sincal-balanced.
Multiconductor reader
Use sincal-multiconductor to select the conductor-resolved reader. A symmetric
operating point still produces MulticonductorNetwork. The verified electrical
profiles include schema-14.8/15.0 native SQLite/archive inputs and schema-11.5/12.8
Access acquisition records. Shared structural admission of other versions does
not imply their electrical support. Unsupported equipment or missing required
sequence data rejects the complete parse; no partial feeder is returned.
The documented global Flag_LFZ0=2 missing-zero-sequence policy is supported
for three-phase sequence lines and the verified ideal-source profile. Explicit
zero-sequence inputs retain precedence; applied defaults are recorded. This
does not enable missing-data supplementation for transformers or finite sources.
Nominal delta–delta transformers support one, two or three installed coils,
including reversed polarity and open terminals. Winding selectors expand to
actual phase pairs; no unused phase is invented. Partial mixed-winding
transformers and inconsistent native core-loss inputs still reject.
powerio summary case.db --from sincal-multiconductor
powerio convert case.db --from sincal-multiconductor --to pmd-json -o case.json
powerio convert case.db --from sincal-multiconductor --to sincal-multiconductor -o copy.db
Python’s existing parse(..., format="sincal-multiconductor") and the C ABI’s
existing pio_parse route native SQLite/archive inputs to their established
multiconductor typed accessors. No ABI entry point or network family is added.
The Rust facade exposes explicit variant/snapshot/acquisition selection through
ParseOptions.sincal_multiconductor. Python uses dist.SincalReadOptions, and
the CLI exposes the same selections on summary, convert and serialize.
Access parsing requires
the original MDB plus the optional helper’s acquired tables, supplied as a
relative source companion. Parsing does not run MDB Tools. The recorded original
length and SHA-256 must match the MDB; this catches mismatched input files, but
is not an attestation that caller-supplied table contents are authentic.
let mut selection = powerio::dist::SincalReadOptions::default();
selection.variant = Some(1);
selection.snapshot_hours = Some(12.0);
selection.acquired_tables = Some("acquired.json".into());
let mut options = powerio::ParseOptions::default().format("sincal-multiconductor")?;
options.sincal_multiconductor = Some(selection);
let module = powerio::parse_with_options("project/original.mdb", &options)?;
assert!(matches!(module.value(), powerio::PioValue::MulticonductorNetwork(_)));
Ok::<(), Box<dyn std::error::Error>>(())
Create project/acquired.json with evals/sincal/import_access.py. In-memory
sources supply the companion with Source::with_named_buffer; file companions
stay under the source’s acquisition root. For example:
import powerio
from powerio.dist import SincalReadOptions
module = powerio.parse(
"project/original.mdb", format="sincal-multiconductor",
sincal_multiconductor=SincalReadOptions(
variant=1, snapshot_hours=12, acquired_tables="acquired.json"),
)
powerio summary project/original.mdb --from sincal-multiconductor \
--sincal-variant 1 --sincal-snapshot-hours 12 \
--sincal-acquired-tables acquired.json
Python memory inputs supply named_buffers={"acquired.json": records_bytes}.
They never read companions from disk. File inputs may explicitly widen the
root with acquisition_root=... in Python or --acquisition-root in the CLI;
the root must contain the primary and referenced files. The normal root is the
primary file’s parent directory. Julia uses the same keywords with its exported
SincalReadOptions:
using PowerIO
module_ = parse("project/original.mdb"; format="sincal-multiconductor",
sincal_multiconductor=SincalReadOptions(
variant=1, snapshot_hours=12, acquired_tables="acquired.json"))
Julia memory/IO inputs take named_buffers=Dict("acquired.json" => records_bytes).
C uses pio_parse_with_options with borrowed PioParseOptions and
PioSincalReadOptions; zero initialization leaves optional values absent, and
presence flags distinguish an omitted snapshot from explicit midnight. The
existing pio_parse remains unchanged. For memory inputs,
pio_source_from_memory_with_buffers copies the primary and named companions
before returning; caller buffers may then be released. These additions require
the matching development library and Julia companion. Existing ABI 7 layouts
and typed network accessors are unchanged.
Legacy UI-manipulator references on loads retain their IDs as provenance. Their edits are already stored in the load input fields, so stored power factors apply once; the UI definition is not evaluated again. This follows Siemens Release Notes 21.0, pp. 4–6. Conflicting daily timestamps remain errors.
Active daily profiles require an explicit snapshot; no midnight default is
assumed. In schema 11.5, absolute P/Q profiles replace aggregate powers, while
common relative-factor profiles scale the defined powers, preserving unequal
Wye or delta branches and their voltage dependence. Relative profiles currently
require the documented direct-scaling coefficient settings: Power_a1=0,
Power_b1=0, Reduce_a2=0, Reduce_b2=1. They accept finite nonnegative factors,
linear or step interpolation and cyclic repetition. Separate P/Q-factor modes,
topology-dependent coincidence and absolute-profile allocation to unequal
branches remain unsupported. Generic time-series and inherited variants remain
under development.
Schema-11.5 NULL transformer tap status uses the documented fixed-status default and records that interpretation. Active controllers and unresolved partial mixed-winding circuits still reject; the default does not supply missing physics.
Fixed reactor and capacitor banks retain their phase connections, losses,
grounding and open/inactive states as typed shunts and switches. Supported
three-phase grounded banks retain separate positive- and zero-sequence inputs.
Explicit neutral impedances, automatic regulators and stepped direct
zero-sequence impedances still require additional mapping. Documented optional
schema-11.5 defaults are recorded; required ratings are never filled in.
The Access acquisition helper includes both bank tables by default.
For schema 11.5, a NULL voltage-level line/cable temperature uses its documented
20 C default. The selected field is recorded in network.defaulted; explicit
temperatures retain their correction, and missing columns or modern NULLs fail.
The same legacy profile admits documented defaults for optional line flags,
dielectric losses, parallel counts, rating factors, rated frequency and active
temperature coefficients. Required impedances and sequence declarations remain
strict. Ideal connections record their applied defaults as well.
Every SINCAL parse shares a fixed budget of SQLite work. Both readers read terminals once per parse and group them by element, so the work per element does not grow with the size of the terminal table: a native-width feeder with 1,000 lines reads within the budget. A project that does exceed it fails with a message saying it exceeds the reader’s bounded query work, never with partial output.
Access MDB inputs use the core primary-file limit, which defaults to 1 GiB;
POWERIO_MAX_PRIMARY_BYTES can set an explicit bound. CSIRO09 is 69,181,440
bytes, and its validation uses that exact, tighter bound. Native SQLite/.sinx
acquisition and acquired table documents retain their separate fixed 64 MiB
limits. These are distinct limits; the library does not silently raise them.
Fidelity and output
In the balanced profile, native physical quantities use a declared 100 MVA
internal conversion base. The multiconductor model uses its usual SI units.
Both readers correct cable resistance for the voltage-level temperature in
every schema. The balanced reader refuses a line built from LineSeg
sections, as the multiconductor reader does. Both readers apply Line.fr as
a factor on the thermal current Ith: the line’s current limit is
Ith * ParSys * fr, and fr does not change its impedance.
Disabled native generator capability limits become unbounded typed limits,
not zero capability. Diagnostics identify this and data outside the chosen
snapshot. Disabled modern profile references do not replace static powers.
Active profiles require a supported adapter and explicit snapshot selection;
currently only the declared schema-11.5 absolute daily profile is accepted.
Fault, dynamic, protection, economic, untyped diagram and stored-result
data remain in the retained source. Selected drawing coordinates are typed as described below. Cross-format output reports their omission.
An unchanged module can emit sincal or its matching explicit profile token
to reproduce its primary native bytes exactly. A SQLite input echoes SQLite
bytes; an archive echoes archive bytes; an explicitly acquired Access case
echoes the original MDB, never the intermediate tables. An explicit output
profile for the other network family is refused. Use an appropriate destination filename:
powerio convert case.sinx --from sincal-balanced --to sincal-balanced -o copy.sinx
This is source echo, not a fresh writer: format metadata reports can_emit=false.
Editing the value removes its retained native source. PowerIO IR retains typed
values and provenance, not the original native project bytes. Edited,
constructed and IR-restored modules therefore refuse native output through
ordinary emit. Fresh writing requires the explicit experimental option below.
Access/MDB acquisition currently uses the explicit optional helper under
evals/sincal; ordinary library parsing never starts external programs. Its
internal typed records are not native SQLite output. The Rust balanced selection
API accepts them as a companion to their original MDB.
Experimental fresh writer (Rust)
emit_with_options accepts an explicit sincal_experimental request. It always
writes the current typed value, even when an unchanged module retains native
source bytes. The result has Fidelity::Canonical, experimental warnings and
loss diagnostics. Default options are equivalent to ordinary emit, including
byte-exact echo. Unsupported physics or packaging errors produce no partial
file, and existing destination files are not overwritten.
let module = powerio::parse_with_options(
"case.sinx", &powerio::ParseOptions::default().format("sincal-balanced")?,
)?;
let mut request = powerio::SincalExperimentalOptions::default();
request.container =
powerio::SincalContainer::archive_with("converted", powerio::ArchiveOptions::default());
let mut options = powerio::EmitOptions::default();
options.sincal_experimental = Some(request);
let result = powerio::emit_with_options(&module, "sincal", &options, "fresh.sinx")?;
assert_eq!(result.fidelity(), powerio::Fidelity::Canonical);
for diagnostic in result.diagnostics() {
eprintln!("{}: {}", diagnostic.code(), diagnostic.message());
}
Ok::<(), Box<dyn std::error::Error>>(())
SincalContainer::Sqlite (the default) produces a single SQLite database.
SincalContainer::archive_with produces deterministic candidate .sinx
packaging containing that database and manifests. ArchiveOptions has no
fields yet; it starts from Default so packaging options can be added later
without breaking callers. The struct variant SincalContainer::Archive { project_name } is kept for compatibility and packages the same bytes. The project name accepts 1–128 ASCII letters, digits,
underscores or hyphens. The destination filename does not select the container.
Neither path writes an Access database, desktop .sin file, diagrams or results.
Native SINCAL open/save/calculation remains an external acceptance gate.
The module’s existing electrical type selects the backend. BalancedNetwork
uses the transmission writer. MulticonductorNetwork uses the distribution
writer and requires request.nominal_ll_volts: a map from every typed bus ID
to a finite positive line-line voltage in volts. Transformer auxiliary buses
that are eliminated during primitive reconstruction span two voltage levels;
their entries may be omitted. No source voltage, bound or metadata value is
silently interpreted as bus nominal voltage. A balanced network rejects this
map. Explicit sincal-balanced and sincal-multiconductor targets reject a
value from the other family; the bare sincal target uses the typed family. Neither electrical
family is transformed implicitly or retried through the other backend.
The initial balanced subset covers ideal reference sources, fixed PQ injections, static loads, same-voltage lines and fixed two-winding transformers. The multiconductor subset covers ideal positive-sequence sources with grounded or isolated floating reference, unequal phase and phase-pair static loads, sequence-representable lines and finite DD or solid DY/YD transformers with fixed taps. Supported native transformer primitives can be rewritten from their actual conductor matrices, including after IR restoration and compatible edits. Reconstruction reports its canonical nameplate parameter base explicitly. External neutral circuits, other transformer/core modes, general shunts, controls and profiles are not yet covered by this writer subset.
Open switches on canonical phase selections retain separate endpoints and explicit open native terminal states. Optional uniform ampacities are preserved. Native readback may introduce auxiliary buses and ideal connections; closed-switch collapse can omit those connections’ ratings on a subsequent fresh write, with loss diagnostics. Neutral switching, conductor permutations and nonuniform switch ratings remain unsupported.
This opt-in is currently exposed by the Rust facade. CLI, Python and C emission
continue to use their existing ordinary emission path. can_emit remains false
because the experimental subset is not a universal native writer. Fresh
multiconductor output is verified through the public reader described above.
Neither internal readback nor independent electrical validation establishes
native SINCAL desktop acceptance.
Validation
The reader maps all 15 nodes and 32 equipment records of the small licensed
SimBench native case. Rust tests cover malformed/unsupported input, service
states, open terminals, typed routing, binary echo and IR behavior. The
evals/sincal/check_balanced_simbench.py harness checks actual Rust output
against paired publisher CSV inputs and a fresh pandapower 3.5.6 calculation,
including derived nonzero taps on either winding. Stored native results are
separate evidence; no SINCAL desktop execution has been performed.
Three external cases also map completely: IEEE18 (18 native nodes, 44 elements), IEEE33 (33 nodes, 67 elements), and the student study (40 nodes, 84 elements). Their fresh independent pandapower comparisons agree within 4.5e-12 pu in complex bus voltage. The student file’s saved static load powers are zero with profiles disabled; its historical profile results are not the state parsed here. The external validation report records this distinction. No external native model files are vendored.
Additional schemas, active profiles, variants and corpus cases remain under development. Native fixtures require redistribution rights; external research models are not silently copied into the test suite.
The public multiconductor facade maps all 688 CSIRO09 elements at five selected
daily snapshots. Its original powers are symmetric; five separately labelled
unequal-delta-branch stress cases exercise asymmetric behavior. Independent
OpenDSS comparisons cover every phase at 617 energized native nodes and four
isolated nodes, with maximum voltage difference below 0.000372 V. The finite
OpenDSS source approximation is checked separately. The same public path checks
original MDB echo and IR value preservation; see evals/sincal/csiro09-public.json.
A second published native case, Truong’s schema-15.0 12-bus model, maps all
45 elements, including 33 unequal single-phase loads. Independent OpenDSS
comparisons cover all 36 phase voltages and 66 line-terminal currents/powers;
maximum voltage error is below 0.000006 V. Native source echo, IR, generic matrix
and PF-instance checks also pass; see evals/sincal/truong12-public.json. Its
source has no redistribution license and remains external. These are two
complete conductor-resolved cases, not complete corpus coverage or native SINCAL
desktop acceptance. The 12-bus case does not close the larger-case review gate.
Explicit balanced Access snapshots
The balanced reader also accepts schema-11.5 Access acquisition records through
powerio_tnd::formats::sincal::SincalBalancedReadOptions, carried by
powerio::ParseOptions::sincal_balanced. Select sincal-balanced explicitly,
set variant and snapshot_hours when required, and set acquired_tables to
the relative companion containing import_access.py output. Memory sources attach
that companion with Source::with_named_buffer; file sources use the acquisition
root. Parsing verifies the original MDB header, byte count and SHA-256 against
those records and never invokes MDB Tools. Include NetworkGroup and
NetworkGroupTrans in acquisition so balanced interchange controls are checked.
CSIRO19 is checked at seven daily snapshots through this public path. Profiles currently admit absolute daily P/Q with linear or stepped interpolation. Modern active profiles, inherited variants and other profile modes still reject. Legacy voltage/temperature defaults are narrowly scoped and retained in component metadata. The CLI uses the same selection flags for either explicit family:
powerio serialize original.mdb --from sincal-balanced --sincal-variant 1 \
--sincal-snapshot-hours 6 --sincal-acquired-tables acquired.json
The acquired companion must be beneath the source directory or the explicitly
selected --acquisition-root. Unknown or missing profiles never trigger a
balanced/multiconductor fallback. Python exposes SincalBalancedReadOptions
through parse(..., sincal_balanced=...); Julia uses the same type and keyword.
C uses PioSincalBalancedReadOptions through PioParseOptions.sincal_balanced.
The separate distribution selection type remains SincalReadOptions.
import powerio as pio
module = pio.parse("project/original.mdb", format="sincal-balanced",
sincal_balanced=pio.SincalBalancedReadOptions(
variant=1, snapshot_hours=12, acquired_tables="acquired.json"))
pio.serialize(module, "case.pio.json")
Experimental legacy source-control compatibility
Rust SincalReadOptions.assume_inactive_source_controls = true and the CLI
--sincal-assume-inactive-source-controls allow schema-11.5 NULL values in
Infeeder.Flag_LfLimit, Flag_LfCtrl, Flag_Qctrl, Flag_Macro and Kr to be
interpreted as zero/inactive. The default remains strict. Python and Julia expose the same boolean on
SincalReadOptions; C exposes it on PioSincalReadOptions. It is unavailable
on balanced reader options.
Active controls, missing columns and missing electrical parameters still reject.
powerio summary project/original.mdb --from sincal-multiconductor \
--sincal-acquired-tables acquired.json --sincal-variant 1 \
--sincal-snapshot-hours 12 --sincal-assume-inactive-source-controls
An applied assumption emits READ.DIST.SINCAL_ASSUMED_INACTIVE_SOURCE_CONTROLS.
The affected component and fields survive IR serialization in
extras.sincal_compatibility_assumptions. Original MDB echo remains byte exact.
These assumptions admit the complete CSIRO12 feeder, with independent OpenDSS
checks, but do not establish what native SINCAL does with these NULLs.
Native node records with no declared equipment conductors are retained in
extras.sincal_unconnected_nodes, with READ.DIST.SINCAL_UNCONNECTED_NODES,
instead of inventing phases. Nodes attached to open or inactive equipment remain
electrical buses; unsourced islands still require explicit downstream handling.
Fidelity findings and working trial routes
Both readers report source-only tables with row counts and an explicit scope (selected native variant or all rows). Enumerated source-only harmonic and reliability fields are named separately; this is not an exhaustive field-level schema audit. Access tables excluded during acquisition have unknown counts, reported as such. Findings have structured diagnostic details, survive IR, and are attached to ordinary cross-format loss warnings. The inventory is a parse-time description, not a copy of the native payload.
Balanced schema defaults identify affected components and values. Distribution
defaults identify components and fields in sincal_defaulted_fields extras;
experimental assumptions remain separately identified. Retained native bytes
are absent from IR, and neither IR nor edited values can recreate native echo.
The installed-wheel trial harness evals/sincal/check_trial_workflows.py
checks these public paths on external models. All four cases preserve original
source echo and typed IR. Matrix and numerical evidence is in the separate
case-specific Rust/oracle harnesses.
| Case / selected profile | PF instance preparation | Ordinary target emission and reparse |
|---|---|---|
| CSIRO19 / balanced, noon snapshot | Pass | MATPOWER pass, with loss diagnostics |
| Truong12 / multiconductor | Pass | DSS, PMD JSON and BMOPF JSON pass, with loss diagnostics |
| CSIRO09 / multiconductor, noon snapshot | Refused: unsourced native islands | Refused: reference-terminal voltage sources |
| CSIRO12 / multiconductor, noon snapshot, compatibility opt-in | Pass | Refused: reference-terminal voltage sources |
Emission/reparse here establishes a usable format path, not numerical equality of the exported target. The OpenDSS numerical oracles independently construct circuits from native SINCAL fields; they do not validate PowerIO’s target exports. PF preparation constructs a calculation instance; PowerIO does not solve it.
For distribution Access cases, keep the original and acquired records together:
import powerio as pio
module = pio.parse("project/original.mdb", format="sincal-multiconductor",
sincal_multiconductor=pio.dist.SincalReadOptions(
variant=1, snapshot_hours=12, acquired_tables="acquired.json",
assume_inactive_source_controls=True)) # CSIRO12 only; inspect diagnostics
print(pio.diagnostic_records(module.diagnostics))
pio.serialize(module, "case.pio.json")
instance = module.to_mc_ac_pf_instance() # CSIRO12 succeeds; CSIRO09 rejects islands
CSIRO09’s primary file is 69,181,440 bytes. The checked command sets
POWERIO_MAX_PRIMARY_BYTES=69181440 explicitly; the default input limit remains
unchanged. The native models stay external, subject to their own data rights.
Drawing coordinates and line routes
Both reader families populate the existing bus-location and line-route fields
from native graphic tables. A declared schematic view (GraphicAreaTile.Flag=2)
uses Diagram space; other views remain Unknown. This profile does not
infer WGS84, a projected CRS, or the meaning of Node.lat/lon
and Node.hr/hh. Use them as native layouts unless you independently establish
the coordinate reference system.
A point-shaped node keeps its source point. An extended busbar uses a derived
midpoint; extras.sincal_geometry preserves its two native endpoints. Lines use
native terminal identities and attachment positions, with ordered bends on
both ports (NoPoint=1..n), following the Siemens database-interface manual.
Gaps, duplicate orders and collapsed routes are diagnosed and omitted.
Conflicting drawings, invalid optional records and multiple areas do not change
the electrical model. No position is fabricated for generated auxiliary buses.
SQLite databases and .sinx archives supply graphics directly. For Access,
include optional graphics in the explicitly acquired companion:
python evals/sincal/import_access.py model.mdb acquired.json --include-graphics
Keep any additional electrical table selections your case already requires.
Electrical-only companions still work; omitted graphics are reported.
READ.SINCAL.GEOMETRY or READ.DIST.SINCAL_GEOMETRY reports the mapping counts,
coordinate space and any omissions. View identity, origin, page dimensions,
scales and optional CRS/reference fields are retained as native values in
the module’s SINCAL view metadata extension and survive IR (the full extension
key is documented in the implementation guide below). No origin or
scale transform is applied; page centimetres do not define a metre-space canvas.
Graphical style and artwork remain
only in source. Unchanged native echo stays byte-exact; IR retains mapped geometry.
Fresh experimental SINCAL output still omits it with a diagnostic.
Existing extraction paths work without new options or binding types:
powerio geo extract case.sinx --from sincal-balanced -o case.geo.json
powerio geo extract case.db --from sincal-multiconductor -o case.geo.json
For Access or another input requiring snapshot/compatibility selections, first
serialize the selected module to IR, then extract that IR’s geometry. Canonical
geo JSON carries Diagram or Unknown space; it is not an earth-referenced GIS
layer. Full native view metadata is retained on the module and in IR, rather
than on the extracted geometry layer.
Rust uses BalancedNetwork::to_geo_layer() or
powerio::dist_geo::to_dist_geo_layer(&network).
Validation covers SimBench, CSIRO09/12/19 and the externally held Truong model: 862 typed locations and 674 routes, including three native bends. All preserve electrical fields, native echo and IR. CSIRO12 retains its existing explicit compatibility assumptions. Additional shared-decoder checks cover CSIRO03 (774 routes, up to 40 vertices) and CSIRO13 (874 routes); these are geometry-only checks and do not claim complete electrical parsing of either case. See the implementation and evidence for case accounting and the deferred georeferencing and desktop acceptance gates.