Skip to content

The Cartographer

What It Is

The Cartographer is a runnable demo: a real browser-executed DAG application, not a decorative diagram. It is a deterministic data-orchestration pipeline powered by Dagonizer: multi-source fan-in, branching conditional routing, offline country-coder geo-resolution, GDPR redaction, and continent insights. It uses the same engine as the Archivist, applied to ETL instead of LLM agents.

Use it to see data-pipeline work stay inspectable, resumable, and honest about skipped work. The graph shows which branches run, which branches are skipped, and which embedded DAGs own each transformation.

How It Works

The runner wires real node classes, real DAG documents, and browser UI observers together. The visual panes listen to dispatcher lifecycle events, so the page shows execution rather than replaying a canned animation.

Architecture

One top-level scatter and a tree of per-type embedded pipeline DAGs:

cartographer (top-level)
  entrypoints: position-ping | facility-scan | sensor-reading | customs-event | delivery-confirmation
  gather('intake-gather', source-intake)     ← multi-input source intake; writes merged state.sources stream
  scatter('process-stream', 'sources',       ← one run of stream-event per source payload
          { dag: 'stream-event' },
          gather: insights-fold,             ← O(1) fold into state.insights / state.journeys / state.sampleRecords
          container: 'cpu',                  ← browser demo: WebWorkerContainer role
          execution: { mode: 'reservoir', concurrency: 16, reservoir: { keyField: 'eventType', capacity } })
    └─ stream-event                          ← decode-payload → route-event-type-variant
         ├─ position-ping       ──► pipeline-position-ping    (parse → geo-pipeline → enrich-leg → aggregate)
         ├─ sensor-reading      ──► pipeline-sensor-reading   (parse → geo-pipeline → cold-chain → enrich-leg → aggregate)
         ├─ customs-event       ──► pipeline-customs-event    (parse → geo-pipeline → customs-dwell → enrich-leg → aggregate)
         ├─ facility-scan       ──► pipeline-facility-scan    (parse → geo-pipeline → canonicalize-facility
         │                                                      → order-enrichment → gdpr-compliance → aggregate)
         └─ delivery-confirmation ► pipeline-delivery-confirmation (parse → geo-pipeline → canonicalize-recipient
                                                                    → confirm-delivery → gdpr-compliance → aggregate)
         Each per-type pipeline embeds:
           geo-pipeline  ←  route-geo → validate-coords → geo-source-resolve (six embedded resolver DAG entrypoints → geo-weighted-fusion GatherNode) | apply-geo
           gdpr-compliance  ←  consent-gate → classify-pii → redact-pii
  embed('summarize-insights', 'insights-summary',
        container: 'io')                     ← browser demo: separate WebWorkerContainer role
    └─ insights-summary
         summarize → done
  done

The insights-fold gather accumulates each clone's state.enriched into three bounded accumulators (state.insights, state.journeys, state.sampleRecords) as clones complete. Memory is O(1) regardless of event count — the parent state never holds a full copy of every record at once.

The browser demo runs the process-stream scatter body through container role cpu and the summarize-insights embedded DAG through container role io. CartographerWorkerContainer extends WebWorkerContainer to spawn a statically-bundled worker entry so Vite can chunk the registry. The reservoir capacity is a UI-controlled knob: the runner calls CartographerWorkersDag.bundle(clampedBatchCapacity) on each run so the batch size tracks the visitor's setting without mutating shared constants.

Diagrams, Examples, and Outputs

The live demo is the main diagram. Its graph, state panes, traces, memory views, backend selectors, and outputs are all evidence from the running system.

What this proves

The Cartographer proves Dagonizer is not only an agent framework. The same JSON-LD DAG model, scatter/gather machinery, embedded DAGs, worker containers, checkpoint semantics, and visualization surfaces run deterministic ETL/data-orchestration workloads in the browser.

It runs on the same @studnicky/dagonizer engine as The Archivist. Only the node domain differs: agent reasoning vs data enrichment. The DAG topology, lifecycle hooks, observer pattern, streaming scatter, and embedded-DAG composition are identical.

Try it live below. Click Run to stream 21 synthetic tracking events (the default: 6 position-pings, 5 facility-scans, 4 sensor-readings, 3 customs-events, 3 delivery-confirmations) through the full pipeline. Watch the DAG pane: nodes light cyan while executing, edges flash when traversed, and branching skips are visible as edges that never fire.

Watch the Panels tab after the run: the before/after panel shows raw GPS coordinates resolved to a real continent/country, and raw PII fields redacted to their pseudonymised forms. The routing savings table shows how many node executions the conditional branching avoided.

What It Lets You Do

Use the Cartographer when you want to see Dagonizer without an LLM anywhere in the loop. It is a streaming data pipeline with typed inputs, bounded fan-out, conditional routing, worker-backed processing, and aggregate outputs.

For application teams, this page answers a different practical question than the Archivist: can the same graph engine handle ETL-shaped work with real branching, backpressure, and data-quality decisions? Yes, and the panels show the skipped work as clearly as the completed work.

What to try

Click Run and watch the stream, DAG, and panels while synthetic shipment events move through parsing, geo-resolution, GDPR compliance, worker-backed stream processing, and insight aggregation. Compare the routing-savings table with the highlighted DAG path.

Code Samples

The Cartographer source shows the data-pipeline side of the same engine. Start with the top-level DAGs, then inspect the routing nodes, state/services, entity shapes, and CLI runner that make the browser demo deterministic.

Branching conditional routing

Each per-type pipeline DAG routes the event only through the nodes it needs. Two skip conditions are the headline:

  • route-geo: a position-ping that already carries resolved geo (country, continent, region from the JSON source) routes to apply-geo and never enters the geo-source-resolve sub-DAG. The entire source-model geo lookup — offline coords/locale/code resolution and the IP geolocation network call — is skipped.
  • route-redaction: an event with no PII fields, or one whose consent/jurisdiction does not require processing, routes to skip-redaction and never enters the gdpr-compliance sub-DAG.

Each routing node records its decision on the clone's state.routing object (a EnrichedShipment.routing value). The parent delegates summarize-insights to the insights-summary DAG, which folds these across all records to produce the savings tally when the streaming gather has not already produced bounded aggregates.

ts
export class RouteGeoNode extends MonadicNode<CartographerState, 'has-geo' | 'needs-geo'> {
  readonly '@id' = 'urn:noocodec:node:route-geo';
  readonly 'name' = 'route-geo';
  readonly 'outputs' = ['has-geo', 'needs-geo'] as const;

  override get outputSchema(): Record<'has-geo' | 'needs-geo', SchemaObjectType> {
    return {
      'has-geo':   { 'type': 'object' },
      'needs-geo': { 'type': 'object' },
    };
  }

  override async execute(
    batch: Batch<CartographerState>,
    _context: NodeContextType,
  ): Promise<RoutedBatchType<'has-geo' | 'needs-geo', CartographerState>> {
    const acc = new Map<'has-geo' | 'needs-geo', ItemType<CartographerState>[]>();

    for (const item of batch) {
      const result = this.routeItem(item.state);
      for (const error of result.errors) {
        item.state.collectError(error);
      }
      const bucket = acc.get(result.output);
      if (bucket === undefined) {
        acc.set(result.output, [item]);
      } else {
        bucket.push(item);
      }
    }

    const routed = new Map<'has-geo' | 'needs-geo', Batch<CartographerState>>();
    for (const [output, items] of acc) {
      routed.set(output, Batch.from(items));
    }
    return routed;
  }

  private routeItem(state: CartographerState): NodeOutputType<'has-geo' | 'needs-geo'> {
    const geo = state.canonical.geo;
    // A source's pre-resolved geo only lets us skip the lookup when it actually
    // resolved a location — an 'UNK'/'Unmapped' placeholder (e.g. a ping whose
    // coords were out of range at the source) is NOT resolved, so it must run
    // the lookup path where validate-coords can reject the bad coords.
    const hasResolvedGeo =
      geo !== undefined &&
      geo.country.length > 0 &&
      geo.country !== 'UNK' &&
      geo.region.length > 0 &&
      geo.region !== 'Unmapped';

    if (hasResolvedGeo) {
      state.routing = { ...state.routing, 'geoLookupSkipped': true, 'geoLookupRun': false };
      return NodeOutput.create('has-geo');
    }
    state.routing = { ...state.routing, 'geoLookupRun': true, 'geoLookupSkipped': false };
    return NodeOutput.create('needs-geo');
  }
}
ts
export class RouteRedactionNode extends MonadicNode<CartographerState, 'needs-redaction' | 'skip-redaction'> {
  readonly '@id' = 'urn:noocodec:node:route-redaction';
  readonly 'name' = 'route-redaction';
  readonly 'outputs' = ['needs-redaction', 'skip-redaction'] as const;

  override get outputSchema(): Record<'needs-redaction' | 'skip-redaction', SchemaObjectType> {
    return {
      'needs-redaction': { 'type': 'object' },
      'skip-redaction':  { 'type': 'object' },
    };
  }

  override async execute(
    batch: Batch<CartographerState>,
    _context: NodeContextType,
  ): Promise<RoutedBatchType<'needs-redaction' | 'skip-redaction', CartographerState>> {
    const acc = new Map<'needs-redaction' | 'skip-redaction', ItemType<CartographerState>[]>();

    for (const item of batch) {
      const result = this.routeItem(item.state);
      for (const error of result.errors) {
        item.state.collectError(error);
      }
      const bucket = acc.get(result.output);
      if (bucket === undefined) {
        acc.set(result.output, [item]);
      } else {
        bucket.push(item);
      }
    }

    const routed = new Map<'needs-redaction' | 'skip-redaction', Batch<CartographerState>>();
    for (const [output, items] of acc) {
      routed.set(output, Batch.from(items));
    }
    return routed;
  }

  private routeItem(state: CartographerState): NodeOutputType<'needs-redaction' | 'skip-redaction'> {
    const ev = state.currentEvent;
    const hasPii =
      state.canonical.pii === true ||
      ev.recipientName.length > 0 ||
      ev.recipientEmail.length > 0;
    const alreadyHandled = state.canonical.consentHandled === true;

    const consentStatus = Consent.statusFor(ev.shipmentId, ev.marketingConsent);
    const juris = state.geoContext.jurisdiction;
    const lightRegime = juris === 'baseline' || juris === 'international-waters';
    // Light regime + valid consent imposes no redaction obligation.
    const notRequired = lightRegime && consentStatus === 'valid';

    const skip = !hasPii || alreadyHandled || notRequired;

    if (skip) {
      state.routing = { ...state.routing, 'redactionSkipped': true, 'redactionRun': false };
      // Set a minimal no-op GdprResult: redaction NOT applied, precise coords
      // retained. Marketing analytics eligibility still tracks valid consent.
      state.gdprResult = {
        ...state.gdprResult,
        'consentStatus':              consentStatus,
        'lawfulBasis':                state.raw.lawfulBasis,
        'jurisdiction':               state.geoContext.jurisdiction,
        'redactionApplied':           false,
        'coordsCoarsened':            false,
        'marketingAnalyticsEligible': consentStatus === 'valid',
      };
      return NodeOutput.create('skip-redaction');
    }
    state.routing = { ...state.routing, 'redactionRun': true, 'redactionSkipped': false };
    return NodeOutput.create('needs-redaction');
  }
}

export const routeRedaction = new RouteRedactionNode();

The DAGs

Top-level: cartographer

ts
/**
 * cartographerDAG: multi-entry source intake gather over raw source payloads.
 *
 * Five canonical entrypoint IRIs target intake-gather directly. The
 * source-intake gather opens those per-type streams and merges them into
 * state.sources.
 * The processing scatter reads that merged stream at concurrency 16, runs
 * stream-event per item, and folds completed
 * clone state through insights-fold. Memory is O(1) regardless of event count.
 *
 * Topology:
 *   5 data-type entrypoints → gather('intake-gather', source-intake)
 *     → scatter('process-stream', 'sources', { dag: 'stream-event' }, concurrency: 16)
 *     → gather('fold-insights', strategy: insights-fold)
 *     → summarize → done
 */
export const cartographerDAG: DAGType = new DAGBuilder(CARTOGRAPHER_DAG_IRI, '1.0')

  .gather(
    CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
    CARTOGRAPHER_IRIS.intakeSources(CARTOGRAPHER_DAG_IRI),
    { 'strategy': 'source-intake' },
    {
      'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream'),
      'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream'),
      'empty':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'done'),
    },
  )

  .scatter(
    CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream'),
    'sources',
    { 'dag': STREAM_EVENT_DAG_IRI },
    {
      'all-success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'),
      'partial':     CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'),
      'all-error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'),
      'empty':       CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize'),
    },
    {
      'itemKey':     'source-payload',
      'execution': { 'mode': 'reservoir', 'concurrency': 16, 'reservoir': { 'keyField': 'eventType', 'capacity': 1000 } },
    },
  )
  .gather(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'), {
    [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream')]: {},
  }, { 'strategy': 'insights-fold' }, {
    'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize'),
    'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize'),
    'empty':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize'),
  })

  // Pass-through in the streaming path (insights-fold already populated
  // state.insights, state.journeys, and state.sampleRecords). Falls back
  // to the records-based fold for non-streaming callers.
  .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize'), summarizeInsights, {
    'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'done'),
  })

  .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'done'), { outcome: 'completed' })

  .entrypoints({
    'position-ping':          CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
    'facility-scan':          CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
    'sensor-reading':         CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
    'customs-event':          CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
    'delivery-confirmation':  CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
  })

  .build();

Worker-role top-level: cartographer

ts
/** Default reservoir capacity for the process-stream scatter in the workers DAG. */
export const DEFAULT_RESERVOIR_CAPACITY = 1000;

/**
 * CartographerWorkersDag: static factory for the cartographer-workers DAG and
 * its associated dispatcher bundle. Consumers call CartographerWorkersDag.build()
 * (DAG only) or CartographerWorkersDag.bundle() (full dispatcher bundle) with an
 * optional reservoir capacity override.
 *
 * DAG topology — identical to cartographerDAG with containerized boundaries:
 *   - container: 'cpu' so each stream-event body runs inside a
 *     WorkerThreadContainer/WebWorkerContainer rather than in-process.
 *   - container: 'io' so the final summary runs through the same embedded-DAG
 *     interface used by plugins and nested flows.
 *   - reservoir.capacity is parameterised; callers pass their UI-controlled
 *     batch size rather than relying on the compile-time default.
 *
 *   5 data-type entrypoints → gather('intake-gather', source-intake)
 *     → scatter('process-stream', 'sources', { dag: 'stream-event' },
 *               concurrency: 16, container: 'cpu', reservoir: { capacity })
 *     → gather('fold-insights', strategy: insights-fold)
 *     → embed('summarize-insights', 'insights-summary', container: 'io')
 *     → done
 */
export class CartographerWorkersDag {
  private constructor() { /* static-only */ }

  /**
   * Build the cartographer-workers DAG with the given reservoir capacity.
   * CLI, smoke tests, and dag-validate consumers use cartographerWorkersDAG
   * (the pre-built constant); the browser demo calls this with a UI-controlled value.
   */
  static build(capacity: number = DEFAULT_RESERVOIR_CAPACITY): DAGType {
    return new DAGBuilder(CARTOGRAPHER_DAG_IRI, '1.0')

      .gather(
        CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
        CARTOGRAPHER_IRIS.intakeSources(CARTOGRAPHER_DAG_IRI),
        { 'strategy': 'source-intake' },
        {
          'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream'),
          'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream'),
          'empty':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'failed'),
        },
      )

      .scatter(
        CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream'),
        'sources',
        { 'dag': STREAM_EVENT_DAG_IRI },
        {
          'all-success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'),
          'partial':     CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'),
          'all-error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'),
          'empty':       CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize-insights'),
        },
        {
          'itemKey':     'source-payload',
          'container':   'cpu',
          'execution': { 'mode': 'reservoir', 'concurrency': 16, 'reservoir': { 'keyField': 'eventType', 'capacity': capacity } },
        },
      )
      .gather(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'fold-insights'), {
        [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'process-stream')]: {},
      }, { 'strategy': 'insights-fold' }, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize-insights'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize-insights'),
        'empty':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize-insights'),
      })

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'summarize-insights'), INSIGHTS_SUMMARY_DAG_IRI, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'done'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'failed'),
      }, {
        'container': 'io',
      })

      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'done'), { outcome: 'completed' })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'failed'), { outcome: 'failed' })

      .entrypoints({
        'position-ping':          CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
        'facility-scan':          CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
        'sensor-reading':         CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
        'customs-event':          CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
        'delivery-confirmation':  CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_DAG_IRI, 'intake-gather'),
      })

      .build();
  }

  /**
   * Build the workers bundle with a configurable reservoir capacity. The returned
   * bundle is identical to cartographerWorkersBundle except that its cartographer
   * DAG is built with CartographerWorkersDag.build(capacity) so the process-stream
   * scatter uses the caller-supplied batch size.
   *
   * Used by the browser demo to wire UI-controlled knobs into each run() without
   * mutating the shared default-capacity constants.
   */
  static bundle(
    capacity: number = DEFAULT_RESERVOIR_CAPACITY,
  ): DispatcherBundleType<CartographerState> {
    return {
      'nodes': [
        ...cartographerWorkerRuntimeBundle.nodes,
      ],
      'dags': [
        ...cartographerWorkerRuntimeBundle.dags,
        CartographerWorkersDag.build(capacity),
      ],
    };
  }
}

/**
 * cartographerWorkersDAG: pre-built workers DAG at DEFAULT_RESERVOIR_CAPACITY.
 * CLI, smoke tests, and dag-validate consumers use this constant; the browser
 * demo uses CartographerWorkersDag.build(capacity) with a UI-controlled value.
 */
export const cartographerWorkersDAG: DAGType = CartographerWorkersDag.build();

Summary body: insights-summary

ts
/**
 * insights-summary: embedded summary body for the browser workers topology.
 *
 * The top-level workers DAG delegates this single-cardinality stage to the
 * `io` container role after the `cpu` scatter finishes. The body is the same
 * summarizeInsights node used by the in-process cartographer DAG, packaged as a
 * registered DAG so the worker registry and JSON-LD assembly use the same
 * canonical embed/plugin surface.
 */
export const insightsSummaryDAG: DAGType = new DAGBuilder(INSIGHTS_SUMMARY_DAG_IRI, '1.0')
  .node(CARTOGRAPHER_IRIS.placementIri(INSIGHTS_SUMMARY_DAG_IRI, 'summarize'), summarizeInsights, {
    'success': CARTOGRAPHER_IRIS.placementIri(INSIGHTS_SUMMARY_DAG_IRI, 'done'),
  })
  .terminal(CARTOGRAPHER_IRIS.placementIri(INSIGHTS_SUMMARY_DAG_IRI, 'done'), { outcome: 'completed' })
  .build();

Branching enrichment: event-pipeline-typed

ts
/**
 * event-pipeline-typed: the live enrichment scatter body for process-events.
 *
 * Reads the scattered CanonicalEventVariant from metadata key 'canonical-event'
 * and routes it to one of five per-type embedded DAGs via route-event-type-variant.
 * Each per-type DAG starts with parse-variant (which also reads from metadata),
 * embeds geo-pipeline for geo resolution, runs type-specific enrichment nodes,
 * and converges on aggregate-event → done.
 *
 *   route-event-type-variant
 *     ├─position-ping──────────► pipeline-position-ping (embedded)
 *     ├─sensor-reading─────────► pipeline-sensor-reading (embedded)
 *     ├─customs-event──────────► pipeline-customs-event (embedded)
 *     ├─facility-scan──────────► pipeline-facility-scan (embedded)
 *     └─delivery-confirmation──► pipeline-delivery-confirmation (embedded)
 *   Each per-type DAG:
 *     parse-variant → geo-pipeline → canonicalize-core → [type-specific] → aggregate-event → done
 *
 * Metadata propagation: the scatter sets 'canonical-event' on each clone's
 * metadata. NodeStateBase.clone() copies _metadata, so metadata propagates
 * to embedded child clones. Both route-event-type-variant and parse-variant
 * read 'canonical-event' from metadata.
 */
export const eventPipelineTypedDAG: DAGType = new DAGBuilder(EVENT_PIPELINE_TYPED_DAG_IRI, '1.0')

  // 1. route-event-type-variant: read eventType from 'canonical-event' metadata
  //    and dispatch to the corresponding per-type sub-DAG.
  .node(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'route-event-type-variant'), routeEventType, {
    'position-ping':         CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-position-ping'),
    'sensor-reading':        CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-sensor-reading'),
    'customs-event':         CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-customs-event'),
    'facility-scan':         CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-facility-scan'),
    'delivery-confirmation': CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-delivery-confirmation'),
  })

  // 2a. pipeline-position-ping: geo + leg measurement.
  .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-position-ping'), CARTOGRAPHER_IRIS.dag.pipelinePositionPing, {
    'success': CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'done'),
    'error':   CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'rejected'),
  }, {
    'outputs': {
      'canonicalVariant': 'canonicalVariant',
      'raw':              'raw',
      'normalized':       'normalized',
      'currentEvent':     'currentEvent',
      'geoContext':       'geoContext',
      'resolvedGeo':      'resolvedGeo',
      'legKm':            'legKm',
      'routing':          'routing',
      'enriched':         'enriched',
      'capturedErrors':   'capturedErrors',
    },
  })

  // 2b. pipeline-sensor-reading: geo + cold-chain + leg measurement.
  .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-sensor-reading'), CARTOGRAPHER_IRIS.dag.pipelineSensorReading, {
    'success': CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'done'),
    'error':   CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'rejected'),
  }, {
    'outputs': {
      'canonicalVariant': 'canonicalVariant',
      'raw':              'raw',
      'normalized':       'normalized',
      'currentEvent':     'currentEvent',
      'geoContext':       'geoContext',
      'resolvedGeo':      'resolvedGeo',
      'coldChainBreach':  'coldChainBreach',
      'legKm':            'legKm',
      'routing':          'routing',
      'enriched':         'enriched',
      'capturedErrors':   'capturedErrors',
    },
  })

  // 2c. pipeline-customs-event: geo + customs-dwell + leg measurement.
  .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-customs-event'), CARTOGRAPHER_IRIS.dag.pipelineCustomsEvent, {
    'success': CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'done'),
    'error':   CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'rejected'),
  }, {
    'outputs': {
      'canonicalVariant':  'canonicalVariant',
      'raw':               'raw',
      'normalized':        'normalized',
      'currentEvent':      'currentEvent',
      'geoContext':        'geoContext',
      'resolvedGeo':       'resolvedGeo',
      'customsDwellHours': 'customsDwellHours',
      'legKm':             'legKm',
      'routing':           'routing',
      'enriched':          'enriched',
      'capturedErrors':   'capturedErrors',
    },
  })

  // 2d. pipeline-facility-scan: geo + facility canonicalization + order enrichment
  //     + GDPR-gated redaction.
  .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-facility-scan'), CARTOGRAPHER_IRIS.dag.pipelineFacilityScan, {
    'success': CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'done'),
    'error':   CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'rejected'),
  }, {
    'outputs': {
      'canonicalVariant':  'canonicalVariant',
      'raw':               'raw',
      'normalized':        'normalized',
      'currentEvent':      'currentEvent',
      'geoContext':        'geoContext',
      'resolvedGeo':       'resolvedGeo',
      'pricedOrder':       'pricedOrder',
      'shippingQuote':     'shippingQuote',
      'deliveryEstimate':  'deliveryEstimate',
      'legKm':             'legKm',
      'gdprResult':        'gdprResult',
      'routing':           'routing',
      'enriched':          'enriched',
      'capturedErrors':   'capturedErrors',
    },
  })

  // 2e. pipeline-delivery-confirmation: geo + recipient canonicalization +
  //     delivery confirmation + GDPR-gated redaction.
  .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'pipeline-delivery-confirmation'), CARTOGRAPHER_IRIS.dag.pipelineDeliveryConfirmation, {
    'success': CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'done'),
    'error':   CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'rejected'),
  }, {
    'outputs': {
      'canonicalVariant': 'canonicalVariant',
      'raw':              'raw',
      'normalized':       'normalized',
      'currentEvent':     'currentEvent',
      'geoContext':       'geoContext',
      'resolvedGeo':      'resolvedGeo',
      'legKm':            'legKm',
      'gdprResult':       'gdprResult',
      'routing':          'routing',
      'enriched':         'enriched',
      'capturedErrors':   'capturedErrors',
    },
  })

  .terminal(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'done'),     { outcome: 'completed' })
  .terminal(CARTOGRAPHER_IRIS.placementIri(EVENT_PIPELINE_TYPED_DAG_IRI, 'rejected'), { outcome: 'failed' })

  .build();

Ingestion sub-DAG: ingest-source

The shared transform node chain. Only the subset each format needs runs; the rest is skipped by the select-source routing node.

ts
/**
 * IngestSourceDAG: orthogonal-compression, per-format-normalize ingestion DAG.
 *
 * Compression is a pre-step independent of format; each format has its own
 * parse node and normalization sub-DAG; all converge on the shared coerce/validate tail.
 *
 *   select-source ─compressed──► decompress ──► route-format
 *                 ─plain─────────────────────► route-format
 *                 ─invalid──────────────────────────────────► rejected
 *
 *   route-format ─csv────► parse-csv    ► [normalize-csv]    ─┐
 *                ─json───► parse-json   ► [normalize-json]   ─┤
 *                ─ndjson─► parse-ndjson ► [normalize-ndjson] ─┤─► coerce-types ─► validate-event ─► ingested
 *                ─yaml───► parse-yaml   ► [normalize-yaml]   ─┘
 *                ─invalid──────────────────────────────────────► rejected
 *
 * Terminals: ingested (completed), rejected (failed — unselectable / bad payload).
 */

// #region ingest-source-dag
import { selectSource }   from '../nodes/ingest/selectSource.ts';
import { decompress }     from '../nodes/ingest/decompress.ts';
import { routeFormat }    from '../nodes/ingest/routeFormat.ts';
import { parseCsv }       from '../nodes/ingest/parseCsv.ts';
import { parseJson }      from '../nodes/ingest/parseJson.ts';
import { parseNdjson }    from '../nodes/ingest/parseNdjson.ts';
import { parseYaml }      from '../nodes/ingest/parseYaml.ts';
import { normalizeCsv }   from '../nodes/ingest/normalizeCsv.ts';
import { normalizeJson }  from '../nodes/ingest/normalizeJson.ts';
import { normalizeNdjson } from '../nodes/ingest/normalizeNdjson.ts';
import { normalizeYaml }  from '../nodes/ingest/normalizeYaml.ts';
import { coerceTypes }    from '../nodes/ingest/coercion.ts';
import { validateEvent }  from '../nodes/ingest/validateEvent.ts';

import { normalizeCsvDAG }   from './NormalizeCsvDAG.ts';
import { normalizeJsonDAG }  from './NormalizeJsonDAG.ts';
import { normalizeNdjsonDAG } from './NormalizeNdjsonDAG.ts';
import { normalizeYamlDAG }  from './NormalizeYamlDAG.ts';

import type { CartographerState }    from '../CartographerState.ts';

import type { DAGType, DispatcherBundleType } from '@studnicky/dagonizer';
import { DAGBuilder, DAGIdentity } from '@studnicky/dagonizer';

const ingestSourceDagIri = 'urn:noocodec:dag:ingest-source' as const;
const normalizeCsvDagIri = 'urn:noocodec:dag:normalize-csv' as const;
const normalizeJsonDagIri = 'urn:noocodec:dag:normalize-json' as const;
const normalizeNdjsonDagIri = 'urn:noocodec:dag:normalize-ndjson' as const;
const normalizeYamlDagIri = 'urn:noocodec:dag:normalize-yaml' as const;
const placement = (placementIdentifier: string): string =>
  DAGIdentity.placementId(ingestSourceDagIri, placementIdentifier);

export const ingestSourceDAG: DAGType = new DAGBuilder(ingestSourceDagIri, '1.0')

  // 1. select-source: read source from scatter metadata; route by compression.
  .node(placement('select-source'), selectSource, {
    'compressed': placement('decompress'),
    'plain':      placement('route-format'),
    'invalid':    placement('rejected'),
  })

  // 2. decompress: base64-decode + gunzip → plain text in state.decodedText.
  //    Format-agnostic: any gzipped format passes through here to route-format.
  .node(placement('decompress'), decompress, {
    'route-format': placement('route-format'),
    'invalid':      placement('rejected'),
  })

  // 3. route-format: dispatch to the format-specific parser.
  .node(placement('route-format'), routeFormat, {
    'csv':     placement('parse-csv'),
    'json':    placement('parse-json'),
    'ndjson':  placement('parse-ndjson'),
    'yaml':    placement('parse-yaml'),
    'invalid': placement('rejected'),
  })

  // 4a. parse-csv: CSV text → state.parsedRecords.
  .node(placement('parse-csv'), parseCsv, {
    'normalized': placement('normalize-csv'),
    'invalid':    placement('rejected'),
  })

  // 4b. parse-json: JSON array → state.parsedRecords.
  .node(placement('parse-json'), parseJson, {
    'normalized': placement('normalize-json'),
    'invalid':    placement('rejected'),
  })

  // 4c. parse-ndjson: NDJSON text → state.parsedRecords.
  .node(placement('parse-ndjson'), parseNdjson, {
    'normalized': placement('normalize-ndjson'),
    'invalid':    placement('rejected'),
  })

  // 4d. parse-yaml: YAML sequence → state.parsedRecords.
  .node(placement('parse-yaml'), parseYaml, {
    'normalized': placement('normalize-yaml'),
    'invalid':    placement('rejected'),
  })

  // 5a. normalize-csv: embedded sub-DAG — apply FieldMap by header name.
  //     The FieldMap is name-keyed, so shuffled CSV column order aligns correctly.
  .embed<CartographerState, CartographerState>(placement('normalize-csv'), normalizeCsvDagIri, {
    'success': placement('coerce-types'),
    'error':   placement('rejected'),
  }, {
    // Embedded DAGs run in an isolated state clone: thread the parsed records
    // and the current source (for its mappingKey) IN, and the aligned records
    // back OUT, or the normalize node sees empty input and nothing merges back.
    'inputs':  { 'parsedRecords': 'parsedRecords', 'currentSource': 'currentSource' },
    'outputs': { 'mappedRecords': 'mappedRecords' },
  })

  // 5b. normalize-json: embedded sub-DAG — apply FieldMap by key name.
  .embed<CartographerState, CartographerState>(placement('normalize-json'), normalizeJsonDagIri, {
    'success': placement('coerce-types'),
    'error':   placement('rejected'),
  }, {
    // Embedded DAGs run in an isolated state clone: thread the parsed records
    // and the current source (for its mappingKey) IN, and the aligned records
    // back OUT, or the normalize node sees empty input and nothing merges back.
    'inputs':  { 'parsedRecords': 'parsedRecords', 'currentSource': 'currentSource' },
    'outputs': { 'mappedRecords': 'mappedRecords' },
  })

  // 5c. normalize-ndjson: embedded sub-DAG — apply FieldMap by key name.
  .embed<CartographerState, CartographerState>(placement('normalize-ndjson'), normalizeNdjsonDagIri, {
    'success': placement('coerce-types'),
    'error':   placement('rejected'),
  }, {
    // Embedded DAGs run in an isolated state clone: thread the parsed records
    // and the current source (for its mappingKey) IN, and the aligned records
    // back OUT, or the normalize node sees empty input and nothing merges back.
    'inputs':  { 'parsedRecords': 'parsedRecords', 'currentSource': 'currentSource' },
    'outputs': { 'mappedRecords': 'mappedRecords' },
  })

  // 5d. normalize-yaml: embedded sub-DAG — apply FieldMap by key name.
  .embed<CartographerState, CartographerState>(placement('normalize-yaml'), normalizeYamlDagIri, {
    'success': placement('coerce-types'),
    'error':   placement('rejected'),
  }, {
    // Embedded DAGs run in an isolated state clone: thread the parsed records
    // and the current source (for its mappingKey) IN, and the aligned records
    // back OUT, or the normalize node sees empty input and nothing merges back.
    'inputs':  { 'parsedRecords': 'parsedRecords', 'currentSource': 'currentSource' },
    'outputs': { 'mappedRecords': 'mappedRecords' },
  })

  // 6. coerce-types: string cells → number / bool / epoch. Shared tail.
  .node(placement('coerce-types'), coerceTypes, {
    'validate-event': placement('validate-event'),
  })

  // 7. validate-event: build CanonicalEvents → state.ingestedEvents. Shared tail.
  .node(placement('validate-event'), validateEvent, {
    'validated': placement('ingested'),
  })

  // Terminals
  .terminal(placement('ingested'), { outcome: 'completed' })
  .terminal(placement('rejected'), { outcome: 'failed' })

  .build();

export const ingestSourceBundle: DispatcherBundleType<CartographerState> = {
  // Normalize DAGs registered FIRST so the embedded-DAG placements above resolve.
  'nodes': [
    selectSource, decompress, routeFormat,
    parseCsv, parseJson, parseNdjson, parseYaml,
    normalizeCsv, normalizeJson, normalizeNdjson, normalizeYaml,
    coerceTypes, validateEvent,
  ],
  'dags': [
    normalizeCsvDAG, normalizeJsonDAG, normalizeNdjsonDAG, normalizeYamlDAG,
    ingestSourceDAG,
  ],
};
// #endregion ingest-source-dag

Source-model geo-resolution sub-DAG: geo-source-resolve

geo-source-resolve has six labeled entrypoints: coords, address, ip, code, phone, and locale. Each entrypoint embeds a small resolver DAG. The resolver DAG prepares a GeoSignalDescriptor when its modality is present, runs the dedicated resolver node, and projects state.candidate into the parent gather record. The parent geo-weighted-fusion GatherNode waits for all six producer labels and folds the candidate records by weight into state.resolvedGeo, state.geoContext, and state.routing.{geoConfidence,geoModalities}. When no candidate resolves, the gather writes the same baseline values directly.

Coords resolution uses GeohashTzMap (a base64-embedded binary geohash→timezone table) as the fast offline path, with CoordTimezone (tz-lookup + @rapideditor/country-coder) as the browser-safe border/gap default path. Address resolution calls the injected AddressGeocoder transport (Nominatim live; deterministic no-answer in the smoke). Both IP and address transports are injected per-call so worker threads own independent instances.

ts
/**
 * GeoSourceResolveDAG: validity-gated weighted multi-entry geo-resolution sub-DAG.
 *
 * The parent DAG has one entrypoint per geo modality. Each entrypoint embeds a
 * modality-specific resolver DAG that prepares its descriptor, resolves the
 * candidate when present, and projects `state.candidate` into a gather record.
 * The first-class `geo-weighted-fusion` gather node is the graph-visible barrier
 * that folds candidates by weight into `state.resolvedGeo`, `state.geoContext`,
 * and `state.routing.{geoConfidence,geoModalities}`. When no signal resolves,
 * the gather writes the baseline values directly.
 *
 * Topology:
 *   entrypoints:
 *     coords  ─► resolve-coords-source  ─success/error─┐
 *     address ─► resolve-address-source ─success/error─┤
 *     ip      ─► resolve-ip-source      ─success/error─┤
 *     code    ─► resolve-code-source    ─success/error─┤─► geo-weighted-fusion
 *     phone   ─► resolve-phone-source   ─success/error─┤
 *     locale  ─► resolve-locale-source  ─success/error─┘
 *   geo-weighted-fusion (gather) ─success/error/empty──► resolved
 *   resolved: terminal (completed)
 *
 * DI: `ipGeolocator` and `addressGeocoder` are injected per-call so each
 * dispatcher (main thread, worker thread) owns its own transport instances.
 */

// #region geo-source-resolve-dag
import { resolveCoords } from '../nodes/geo/resolveCoords.ts';
import { resolveLocale } from '../nodes/geo/resolveLocale.ts';
import { resolveCode } from '../nodes/geo/resolveCode.ts';
import { resolvePhone } from '../nodes/geo/resolvePhone.ts';
import { ResolveIpNode } from '../nodes/geo/resolveIp.ts';
import { ResolveAddressNode } from '../nodes/geo/resolveAddress.ts';
import {
  prepareGeoAddress,
  prepareGeoCode,
  prepareGeoCoords,
  prepareGeoIp,
  prepareGeoLocale,
  prepareGeoPhone,
} from '../nodes/geo/prepareGeoSignal.ts';
import { CARTOGRAPHER_IRIS } from '../cartographerIds.ts';
import type { IpGeolocator } from '../contracts/IpGeolocator.ts';
import type { AddressGeocoder } from '../contracts/AddressGeocoder.ts';
import type { CartographerState } from '../CartographerState.ts';

// Side-effect import: registers 'geo-weighted-fusion' at module load so the
// scatter placement can resolve the strategy name at dispatcher construction.
import '../core/GeoWeightedFusionGather.ts';

import type { DispatcherBundleType } from '@studnicky/dagonizer';
import { DAGBuilder } from '@studnicky/dagonizer';

export class GeoSourceResolveDAG {
  private constructor() { /* static-only */ }

  static build(
    ipGeolocator: IpGeolocator,
    addressGeocoder: AddressGeocoder,
  ): DispatcherBundleType<CartographerState> {
    const resolveIp = new ResolveIpNode(ipGeolocator);
    const resolveAddress = new ResolveAddressNode(addressGeocoder);

    const resolveCoordsDag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoResolveCoords, '1.0')
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCoords, 'prepare-geo-coords'), prepareGeoCoords, {
        'present': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCoords, 'resolve-coords'),
        'missing': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCoords, 'done'),
      })
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCoords, 'resolve-coords'), resolveCoords, { 'resolved': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCoords, 'done') })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCoords, 'done'), { 'outcome': 'completed' })
      .build();

    const resolveAddressDag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoResolveAddress, '1.0')
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveAddress, 'prepare-geo-address'), prepareGeoAddress, {
        'present': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveAddress, 'resolve-address'),
        'missing': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveAddress, 'done'),
      })
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveAddress, 'resolve-address'), resolveAddress, { 'resolved': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveAddress, 'done') })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveAddress, 'done'), { 'outcome': 'completed' })
      .build();

    const resolveIpDag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoResolveIp, '1.0')
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveIp, 'prepare-geo-ip'), prepareGeoIp, {
        'present': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveIp, 'resolve-ip'),
        'missing': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveIp, 'done'),
      })
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveIp, 'resolve-ip'), resolveIp, { 'resolved': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveIp, 'done') })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveIp, 'done'), { 'outcome': 'completed' })
      .build();

    const resolveCodeDag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoResolveCode, '1.0')
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCode, 'prepare-geo-code'), prepareGeoCode, {
        'present': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCode, 'resolve-code'),
        'missing': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCode, 'done'),
      })
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCode, 'resolve-code'), resolveCode, { 'resolved': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCode, 'done') })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveCode, 'done'), { 'outcome': 'completed' })
      .build();

    const resolvePhoneDag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoResolvePhone, '1.0')
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolvePhone, 'prepare-geo-phone'), prepareGeoPhone, {
        'present': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolvePhone, 'resolve-phone'),
        'missing': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolvePhone, 'done'),
      })
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolvePhone, 'resolve-phone'), resolvePhone, { 'resolved': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolvePhone, 'done') })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolvePhone, 'done'), { 'outcome': 'completed' })
      .build();

    const resolveLocaleDag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoResolveLocale, '1.0')
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveLocale, 'prepare-geo-locale'), prepareGeoLocale, {
        'present': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveLocale, 'resolve-locale'),
        'missing': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveLocale, 'done'),
      })
      .node(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveLocale, 'resolve-locale'), resolveLocale, { 'resolved': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveLocale, 'done') })
      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoResolveLocale, 'done'), { 'outcome': 'completed' })
      .build();

    const dag = new DAGBuilder(CARTOGRAPHER_IRIS.dag.geoSourceResolve, '1.0')

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-coords-source'), CARTOGRAPHER_IRIS.dag.geoResolveCoords, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
      }, {
        'gatherResult': { 'resultField': 'candidate' },
      })

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-address-source'), CARTOGRAPHER_IRIS.dag.geoResolveAddress, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
      }, {
        'gatherResult': { 'resultField': 'candidate' },
      })

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-ip-source'), CARTOGRAPHER_IRIS.dag.geoResolveIp, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
      }, {
        'gatherResult': { 'resultField': 'candidate' },
      })

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-code-source'), CARTOGRAPHER_IRIS.dag.geoResolveCode, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
      }, {
        'gatherResult': { 'resultField': 'candidate' },
      })

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-phone-source'), CARTOGRAPHER_IRIS.dag.geoResolvePhone, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
      }, {
        'gatherResult': { 'resultField': 'candidate' },
      })

      .embed<CartographerState, CartographerState>(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-locale-source'), CARTOGRAPHER_IRIS.dag.geoResolveLocale, {
        'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
      }, {
        'gatherResult': { 'resultField': 'candidate' },
      })

      .entrypoints({
        'coords':  CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-coords-source'),
        'address': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-address-source'),
        'ip':      CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-ip-source'),
        'code':    CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-code-source'),
        'phone':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-phone-source'),
        'locale':  CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-locale-source'),
      })

      // First-class gather barrier over all embedded resolver producers.
      .gather(
        CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'geo-weighted-fusion'),
        {
          [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-coords-source')]: {},
          [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-address-source')]: {},
          [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-ip-source')]: {},
          [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-code-source')]: {},
          [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-phone-source')]: {},
          [CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolve-locale-source')]: {},
        },
        { 'strategy': 'geo-weighted-fusion' },
        {
          'success': CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolved'),
          'error':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolved'),
          'empty':   CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolved'),
        },
      )

      .terminal(CARTOGRAPHER_IRIS.placementIri(CARTOGRAPHER_IRIS.dag.geoSourceResolve, 'resolved'), { 'outcome': 'completed' })

      .build();

    return {
      'nodes': [
        prepareGeoCoords,
        prepareGeoAddress,
        prepareGeoIp,
        prepareGeoCode,
        prepareGeoPhone,
        prepareGeoLocale,
        resolveCoords,
        resolveAddress,
        resolveIp,
        resolveCode,
        resolvePhone,
        resolveLocale,
      ],
      'dags': [
        resolveCoordsDag,
        resolveAddressDag,
        resolveIpDag,
        resolveCodeDag,
        resolvePhoneDag,
        resolveLocaleDag,
        dag,
      ],
    };
  }
}
// #endregion geo-source-resolve-dag
ts
export class PrepareGeoSignalNode extends MonadicNode<CartographerState, PrepareGeoSignalOutput> {
  readonly '@id': string;
  readonly 'outputs' = ['present', 'missing'] as const;
  readonly #kind: GeoSignalKind;
  readonly #name: string;

  constructor(id: string, name: string, kind: GeoSignalKind) {
    super();
    this['@id'] = id;
    this.#name = name;
    this.#kind = kind;
  }

  get name(): string {
    return this.#name;
  }

  override get outputSchema(): Record<PrepareGeoSignalOutput, SchemaObjectType> {
    return {
      'present': { 'type': 'object' },
      'missing': { 'type': 'object' },
    };
  }

  override async execute(
    batch: Batch<CartographerState>,
    _context: NodeContextType,
  ): Promise<RoutedBatchType<PrepareGeoSignalOutput, CartographerState>> {
    const present: Array<{ readonly id: string; readonly state: CartographerState }> = [];
    const missing: Array<{ readonly id: string; readonly state: CartographerState }> = [];

    for (const item of batch) {
      const descriptor = this.#descriptor(item.state);
      if (descriptor === null) {
        item.state.candidate = GeoResolutionBuilder.from({ 'source': this.#kind, 'weight': 0 });
        missing.push(item);
      } else {
        item.state.setMetadata('geo-signal', descriptor);
        present.push(item);
      }
    }

    const routed = new Map<PrepareGeoSignalOutput, Batch<CartographerState>>();
    if (present.length > 0) routed.set('present', Batch.from(present));
    if (missing.length > 0) routed.set('missing', Batch.from(missing));
    return routed;
  }

  #descriptor(state: CartographerState): GeoSignalDescriptor | null {
    const body = state.canonical.body;
    switch (this.#kind) {
      case 'coords':
        return Number.isFinite(body.latitude)
          && Number.isFinite(body.longitude)
          && (body.latitude !== 0 || body.longitude !== 0)
          && Math.abs(body.latitude) <= 90
          && Math.abs(body.longitude) <= 180
          ? GeoSignalDescriptorBuilder.from({
            'kind': 'coords',
            'weight': SignalWeight.for('coords'),
            'lat': body.latitude,
            'lng': body.longitude,
          })
          : null;
      case 'address':
        return body.address.length > 0
          ? GeoSignalDescriptorBuilder.from({
            'kind': 'address',
            'weight': SignalWeight.for('address'),
            'address': body.address,
          })
          : null;
      case 'ip':
        return body.ipAddress.length > 0
          ? GeoSignalDescriptorBuilder.from({
            'kind': 'ip',
            'weight': SignalWeight.for('ip'),
            'ipAddress': body.ipAddress,
          })
          : null;
      case 'code':
        return body.countryCode.length > 0
          ? GeoSignalDescriptorBuilder.from({
            'kind': 'code',
            'weight': SignalWeight.for('code'),
            'countryCode': body.countryCode,
          })
          : null;
      case 'phone':
        return body.phone.length > 0 && CallingCode.countryFor(body.phone).length > 0
          ? GeoSignalDescriptorBuilder.from({
            'kind': 'phone',
            'weight': SignalWeight.for('phone'),
            'phone': body.phone,
          })
          : null;
      case 'locale':
        return body.localeTag.length > 0
          ? GeoSignalDescriptorBuilder.from({
            'kind': 'locale',
            'weight': SignalWeight.for('locale'),
            'localeTag': body.localeTag,
          })
          : null;
    }
  }
}

export const prepareGeoCoords = new PrepareGeoSignalNode('urn:noocodec:node:prepare-geo-coords', 'prepare-geo-coords', 'coords');
export const prepareGeoAddress = new PrepareGeoSignalNode('urn:noocodec:node:prepare-geo-address', 'prepare-geo-address', 'address');
export const prepareGeoIp = new PrepareGeoSignalNode('urn:noocodec:node:prepare-geo-ip', 'prepare-geo-ip', 'ip');
export const prepareGeoCode = new PrepareGeoSignalNode('urn:noocodec:node:prepare-geo-code', 'prepare-geo-code', 'code');
export const prepareGeoPhone = new PrepareGeoSignalNode('urn:noocodec:node:prepare-geo-phone', 'prepare-geo-phone', 'phone');
export const prepareGeoLocale = new PrepareGeoSignalNode('urn:noocodec:node:prepare-geo-locale', 'prepare-geo-locale', 'locale');

GDPR compliance sub-DAG: gdpr-compliance

ts
/**
 * GdprComplianceDAG: reusable GDPR compliance sub-pipeline.
 *
 * Internal flow:
 *
 *   consent-gate
 *     └─ classify ──► classify-pii
 *   classify-pii
 *     └─ redact ──► redact-pii
 *   redact-pii
 *     ├─ ok        ──► compliant  (TerminalNode completed → parent routes 'success')
 *     └─ violation ──► violation  (TerminalNode failed   → parent routes 'error')
 *
 * Embedded via:
 *   .embed(gdprPlacementIri, gdprComplianceDagIri,
 *     { 'success': aggregateEventPlacementIri, 'error': gdprViolationPlacementIri },
 *     { 'outputs': { 'currentEvent':'currentEvent', 'gdprResult':'gdprResult' } })
 *
 * The embedded DAG runs in a CLONED child state. Its nodes redact PII on
 * state.currentEvent and write state.gdprResult; the `outputs` mapping copies
 * those two fields back into the parent shipment-pipeline clone when the
 * sub-DAG completes (child-key → parent-path orientation).
 */

// #region gdpr-compliance-dag
import { consentGate, classifyPii, redactPii } from '../nodes/gdprNodes.ts';
import { CARTOGRAPHER_IRIS } from '../cartographerIds.ts';
import type { CartographerState } from '../CartographerState.ts';

import type { DAGType, DispatcherBundleType } from '@studnicky/dagonizer';
import { DAGBuilder } from '@studnicky/dagonizer';

const GDPR_COMPLIANCE_DAG_IRI = CARTOGRAPHER_IRIS.dag.gdprCompliance;

export const gdprComplianceDAG: DAGType = new DAGBuilder(GDPR_COMPLIANCE_DAG_IRI, '1.0')

  // ── 1. consent-gate ──────────────────────────────────────────────────────
  // Resolves the consent status from marketingConsent + simulated expiry.
  // Always routes 'classify' (both consented and non-consented proceed;
  // the consent status drives redaction rules downstream).
  .node(CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'consent-gate'), consentGate, {
    'classify': CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'classify-pii'),
  })

  // ── 2. classify-pii ──────────────────────────────────────────────────────
  // Records which fields are personal/sensitive; no routing decision yet.
  .node(CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'classify-pii'), classifyPii, {
    'redact': CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'redact-pii'),
  })

  // ── 3. redact-pii ────────────────────────────────────────────────────────
  // Applies GdprRedactor.redact. Routes to 'compliant' (ok) or 'violation'.
  .node(CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'redact-pii'), redactPii, {
    'ok':        CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'compliant'),
    'violation': CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'violation'),
  })

  // ── Terminals ─────────────────────────────────────────────────────────────
  .terminal(CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'compliant'), { outcome: 'completed' })
  .terminal(CARTOGRAPHER_IRIS.placementIri(GDPR_COMPLIANCE_DAG_IRI, 'violation'), { outcome: 'failed' })

  .build();
// #endregion gdpr-compliance-dag

export const gdprComplianceBundle: DispatcherBundleType<CartographerState> = {
  'nodes': [consentGate, classifyPii, redactPii],
  'dags': [gdprComplianceDAG],
};

State and services

CartographerState

The mutable clipboard threaded through every node. Top-level fields hold the source feeds, ingested events, gathered records, and insights aggregates. Clone fields hold the per-event enrichment pipeline's intermediate values.

ts
export class CartographerState extends NodeStateBase {
  /** Number of synthetic journeys to generate; part of the checkpoint/resume serialized state. */
  eventCount: number = 200;

  /**
   * Per-event-type feed configuration driving buildTypedFeed / streamTyped. Each
   * entry generates entry.count typed scans of its eventType, encoded across the
   * formats in its formatMix.
   */
  eventConfig: EventTypeConfig = [
    { 'eventType': 'position-ping',         'count': 6, 'formatMix': [{ 'format': 'json',   'compression': 'none', 'weight': 2 }, { 'format': 'yaml', 'compression': 'gzip', 'weight': 1 }] },
    { 'eventType': 'facility-scan',         'count': 5, 'formatMix': [{ 'format': 'csv',    'compression': 'none', 'weight': 2 }, { 'format': 'json', 'compression': 'gzip', 'weight': 1 }] },
    { 'eventType': 'sensor-reading',        'count': 4, 'formatMix': [{ 'format': 'ndjson', 'compression': 'gzip', 'weight': 2 }, { 'format': 'ndjson', 'compression': 'none', 'weight': 1 }] },
    { 'eventType': 'customs-event',         'count': 3, 'formatMix': [{ 'format': 'json',   'compression': 'none', 'weight': 2 }, { 'format': 'csv',  'compression': 'none', 'weight': 1 }] },
    { 'eventType': 'delivery-confirmation', 'count': 3, 'formatMix': [{ 'format': 'json',   'compression': 'none', 'weight': 2 }, { 'format': 'csv',  'compression': 'gzip', 'weight': 1 }] },
  ];

  /**
   * When true, host tooling reports the Cartographer run as streaming. The DAG
   * always assembles source streams through its multi-entry intake gather; this
   * flag remains a UI/CLI display knob.
   */
  useStreamingSource: boolean = false;

  /**
   * Override for the total source-payload count. When > 0, the source-intake
   * gather scales eventConfig before opening per-type streams.
   */
  streamCount: number = 0;

  /**
   * StreamChannel buffer capacity for the streaming source channel.
   * When 0 (default), the channel uses its built-in default capacity (256).
   * Set to 1 to enable genuine per-item backpressure (useful for abort-and-resume
   * scenarios where the producer must not pre-fill the buffer).
   */
  streamChannelCapacity: number = 0;

  /**
   * The multi-format source feeds, assembled by intake-gather. Each is a
   * `{ sourceId, format, mappingKey, eventType, payload }` — a different on-the-wire
   * encoding (JSON / CSV / gzip NDJSON) of a typed scan from the event feed.
   *
   * This field normally holds the merged `AsyncIterable<SourcePayload>` built
   * from five per-type source streams. The engine's scatter accepts that stream
   * directly. Snapshot/restore serialises the array path only; resume rebuilds
   * the async iterable from eventConfig and the scatter cursor.
   */
  sources: SourcePayload[] | AsyncIterable<SourcePayload> = [];

  /**
   * Ingestion fan-in buckets: the `append` gather of the ingestion scatter
   * appends each source clone's `ingestedEvents` array as one element here, so
   * this is one bucket per source. The `merge-events` node flattens it into the
   * unified `canonicalEvents` collection.
   */
  ingestBuckets: CanonicalEventVariant[][] = [];

  /**
   * The unified canonical event collection. Every source's decoded events are
   * flattened into this one array (from `ingestBuckets`); the enrichment scatter
   * then reads it.
   */
  canonicalEvents: CanonicalEventVariant[] = [];

  // ── Per-source ingest slots (used inside a source's ingest sub-DAG clone) ──
  /** The source feed currently being ingested (set from `sources` by select). */
  currentSource: SourcePayload = {
    'sourceId':     '',
    'format':       'json',
    'compression':  'none',
    'mappingKey':   'json-position',
    'eventType':    'position-ping',
    'payload':      '',
  };

  /** Decompressed/raw text of the current source (after `decompress`). */
  decodedText: string = '';

  /** Records parsed from the decoded text (after parse-csv/json/ndjson). */
  parsedRecords: Array<Record<string, unknown>> = [];

  /** Records with source field names mapped to canonical fields (after map-fields). */
  mappedRecords: Array<Record<string, unknown>> = [];

  /** Canonical events validated from this source (after coerce-types + validate-event). */
  ingestedEvents: CanonicalEventVariant[] = [];

  /** The single canonical event (geo/consent mirror) under enrichment in a scatter clone; set/updated by parseVariant. */
  canonical: CanonicalEventVariant = CanonicalEventVariantBuilder.from({});

  /** The discriminated per-type variant under enrichment (typed path; set by parseVariant). The old fat path uses `canonical`. */
  canonicalVariant: CanonicalEventVariant = CanonicalEventVariantBuilder.from({});

  /** Enriched shipment records gathered from scatter clones. */
  records: EnrichedShipment[] = [];

  /**
   * Bounded FIFO sample of enriched scans (cap 200) produced by the
   * insights-fold gather strategy. The gather writes to this field
   * incrementally as scatter clones complete; memory does not grow
   * with event count. In the streaming path state.records stays empty;
   * this field holds the representative sample the UI consumes.
   */
  sampleRecords: EnrichedShipment[] = [];

  /** Fixed-size regional insights aggregate produced by summarizeInsights. */
  insights: Map<string, RegionInsights> = new Map();

  /** Per-journey aggregate (grouped by shipmentId) produced by summarizeInsights. */
  journeys: Map<string, JourneyInsights> = new Map();

  /**
   * In-progress per-journey accumulator map, maintained by the insights-fold gather strategy.
   * Part of durable checkpoint state so accumulations survive process restart on resume.
   */
  journeyAccumulators: Map<string, JourneyAccumulator> = new Map();

  /**
   * Parent-side bounded rollup of captured exceptions, folded by the
   * insights-fold gather from each clone's `state.capturedErrors`. Errors flow
   * scatter→gather as first-class data; the run prints this distribution for
   * analysis. Reset per execution by the gather's `initial`.
   */
  errorRollup: ErrorRollupType = ErrorRollup.empty();

  /** Raw scan from scatter metadata (set by parseEvent). */
  raw: RawShipmentEvent = {
    'shipmentId':          '',
    'scanSeq':             0,
    'rawTimestamp':        '',
    'rawDispatchAt':       '',
    'rawStatus':           '',
    'carrier':             '',
    'ipAddress':           '',
    'localeTag':           '',
    'countryCode':         '',
    'latitude':            0,
    'longitude':           0,
    'legFromLat':          0,
    'legFromLng':          0,
    'originLat':           0,
    'originLng':           0,
    'destLat':             0,
    'destLng':             0,
    'weight':              0,
    'weightUnit':          'kg',
    'recipientName':       '',
    'recipientEmail':      '',
    'recipientPhone':      '',
    'recipientAddress':    '',
    'recipientCountry':    '',
    'marketingConsent':    false,
    'rawPromisedDeliveryAt': '',
    'lineItems':           [{ 'productId': '', 'quantity': 1 }],
    'facilityId':          '',
    'lawfulBasis':         'contract',
    'specialCategory':     'none',
    'disruptionReason':    '',
  };

  /** Normalised canonical form (set by normalize node). */
  normalized: NormalizedShipment = {
    'shipmentId':       '',
    'scanSeq':          0,
    'epochMs':          0,
    'dispatchEpochMs':  0,
    'isoTimestamp':     '',
    'localIso':         '',
    'utcOffset':        '',
    'carrierId':        '',
    'carrierName':      '',
    'countryIso3':      'UNK',
    'weightGrams':      0,
    'status':           'SCAN',
    'serviceTier':      'standard',
    'sizeTier':         'small',
    'lineItems':        [{ 'productId': '', 'quantity': 1 }],
    'facilityId':       '',
    'latitude':         0,
    'longitude':        0,
    'legFromLat':       0,
    'legFromLng':       0,
    'originLat':        0,
    'originLng':        0,
    'destLat':          0,
    'destLng':          0,
    'recipientName':    '',
    'recipientEmail':   '',
    'recipientPhone':   '',
    'recipientAddress': '',
    'recipientCountry': '',
    'marketingConsent': false,
    'promisedEpochMs':  0,
    'disruptionHours':  0,
    'disruptionReason': '',
  };

  /**
   * ShipmentEvent-shaped current event used by geo and GDPR nodes.
   * Populated from normalized by the classify node.
   */
  currentEvent: ShipmentEvent = {
    'shipmentId':        '',
    'timestamp':         '',
    'eventType':         'SCAN',
    'latitude':          0,
    'longitude':         0,
    'carrier':           '',
    'facilityId':        '',
    'recipientName':     '',
    'recipientEmail':    '',
    'recipientPhone':    '',
    'recipientAddress':  '',
    'recipientCountry':  '',
    'marketingConsent':  false,
    'promisedDeliveryAt': '',
  };

  /** Geo-enrichment result for the current scan (incl. timezone + jurisdiction). */
  geoContext: GeoContext = {
    'gridZone':     '',
    'country':      '',
    'continent':    'Unmapped',
    'countries':    [],
    'region':       '',
    'hub':          '',
    'status':       'unmapped',
    'waterBodies':  [],
    'timezone':     'UTC',
    'jurisdiction': 'baseline',
  };

  /** Basket pricing result (set by enrich-pricing node). */
  pricedOrder: PricedOrder = {
    'lines':            [],
    'subtotalMinor':    0,
    'currency':         'USD',
    'subtotalUsdMinor': 0,
    'fxRate':           1.0,
  };

  /** Shipping cost + distance (set by enrich-shipping node). */
  shippingQuote: ShippingQuote = {
    'distanceKm':   0,
    'costUsdMinor': 0,
    'breakdown': {
      'baseMinor':      0,
      'perKmMinor':     0,
      'perKgMinor':     0,
      'tierMultiplier': 1.0,
    },
  };

  /** ETA calculation (set by enrich-eta node). */
  deliveryEstimate: DeliveryEstimate = {
    'transitHours':    0,
    'etaEpochMs':      0,
    'etaIso':          '',
    'promisedEpochMs': 0,
    'onTime':          false,
    'delayHours':      0,
  };

  /** Leg distance (legFrom → this scan) in km, set by enrich-leg node. */
  legKm: number = 0;

  /** Cold-chain breach flag (sensor lane only; set by cold-chain-check). */
  coldChainBreach: boolean = false;

  /** Customs clearance dwell hours (customs lane only; set by customs-dwell). */
  customsDwellHours: number = 0;

  /**
   * This scan's conditional-routing decisions (the branching headline). Each
   * routing node records what RAN vs was SKIPPED here; aggregate-event copies it
   * onto the enriched record so the parent's summarize totals the savings (no
   * shared mutable counters across scatter clones).
   */
  routing: EnrichedShipment['routing'] = CartographerState.defaultRouting();

  /**
   * Ephemeral per-clone accumulator of captured exceptions (like ipCandidate:
   * non-serialized, recomputed each dispatch). The geo / ingest nodes append a
   * `GeoErrorRecordType` here whenever their transport reports a captured error;
   * the gather folds these into the parent's `errorRollup`. The node still
   * routes its normal output — the error rides alongside as data.
   *
   * Named `capturedErrors` (not `errors`) to stay distinct from the framework
   * `NodeStateInterface.errors` channel — these are the example's own captured
   * geo/ingest faults, a different concern.
   */
  capturedErrors: readonly GeoErrorRecordType[] = [];

  /** IP-modality candidate from ip-geolocate (unresolved when that node skipped). */
  ipCandidate: GeoCandidate = CartographerState.unresolvedCandidate('ip');

  /** The fused multi-modal location (set by fuse-source-geo). */
  resolvedGeo: ResolvedGeo = {
    'country':      '',
    'countryName':  '',
    'continent':    'Unmapped',
    'region':       '',
    'locality':     '',
    'locale':       '',
    'lat':          0,
    'lng':          0,
    'status':       'land',
    'jurisdiction': 'baseline',
    'confidence':   0,
    'modalities':   [],
    'provenance':   [],
  };

  /** Source-model routing signal built by classify-geo-source (which path to take). */
  geoSignal: GeoSignal = { ...DEFAULT_GEO_SIGNAL };

  /** Resolved geo from the selected source-model path (set by the source-resolve nodes). */
  geoResolution: GeoResolution = { ...DEFAULT_GEO_RESOLUTION };

  /** Scored geo signals for the scatter-gather resolution path (Wave 1+). */
  geoSignals: GeoSignalDescriptor[] = [];

  /** Current best candidate resolution (Wave 1+). */
  candidate: GeoResolution = { ...DEFAULT_GEO_RESOLUTION };

  /** All scored resolution candidates (Wave 1+). */
  geoCandidates: GeoResolution[] = [];

  /** GDPR processing result for the current scan (location + consent driven). */
  gdprResult: GdprResult = {
    'personalDataFields':  [],
    'sensitiveDataFields': [],
    'consentStatus':       'missing',
    'lawfulBasis':         'contract',
    'jurisdiction':        'baseline',
    'strictness':          'light',
    'complianceScore':     0,
    'retention': { 'retainUntil': '', 'autoDelete': false },
    'redactionApplied':    false,
    'marketingAnalyticsEligible': false,
    'coordsCoarsened':     false,
  };

  /** Compact enriched per-scan record written by aggregate-event; parent gather appends it. */
  enriched: EnrichedShipment = {
    'shipmentId':       '',
    'scanSeq':          0,
    'epochMs':          0,
    'localIso':         '',
    'utcOffset':        '',
    'timezone':         'UTC',
    'jurisdiction':     'baseline',
    'continent':        'Unmapped',
    'region':           '',
    'country':          '',
    'hub':              '',
    'geoStatus':        'unmapped',
    'lat':              0,
    'lng':              0,
    'coordsCoarsened':  false,
    'legKm':            0,
    'status':           'SCAN',
    'serviceTier':      'standard',
    'sizeTier':         'small',
    'onTime':           false,
    'exception':        false,
    'consentStatus':    'missing',
    'disruptionReason': '',
    'subtotalUsdMinor': 0,
    'currency':         'USD',
    'shippingUsdMinor': 0,
    'distanceKm':       0,
    'transitHours':     0,
    'delayHours':       0,
    'redactionApplied': false,
    'redactedSample': { 'recipientName': '', 'recipientEmail': '', 'recipientPhone': '' },
    'routing': CartographerState.defaultRouting(),
  };

  override clone(): this {
    const copy = super.clone(); // new Constructor() + _metadata copy from base
    copy.eventCount = this.eventCount;
    copy.eventConfig = this.eventConfig.map((e) => ({ 'eventType': e.eventType, 'count': e.count, 'formatMix': e.formatMix.map((m) => ({ ...m })) }));
    if (Array.isArray(this.sources)) {
      copy.sources = this.sources.map((s) => ({ ...s }));
    } else {
      // AsyncIterable — shared by reference
      copy.sources = this.sources;
    }
    copy.useStreamingSource = this.useStreamingSource;
    copy.streamCount = this.streamCount;
    copy.streamChannelCapacity = this.streamChannelCapacity;
    // Parent-level accumulators: reset to defaults in child clones.
    //
    // ingestBuckets, canonicalEvents, records, sampleRecords, insights, and
    // journeys are scatter-gather accumulators written by the parent DAG's
    // gather strategy (InsightsFoldGather) or by post-scatter summary nodes.
    // Scatter body clones (stream-event, ingestion) never read these fields —
    // they only read the item placed on metadata by the engine. Copying them
    // into clones would send up to 200 EnrichedShipment JSON objects per clone
    // over the worker channel (60 KB × 16,000 in-flight clones = ~960 MB at
    // concurrencyLimit=16 / capacity=1000), producing the O(peak-concurrency)
    // heap spike. Resetting to defaults eliminates that overhead with no loss
    // of correctness: the child never reads them, and the parent retains its
    // own live copies.
    copy.ingestBuckets          = [];
    copy.canonicalEvents        = [];
    copy.records                = [];
    copy.sampleRecords          = [];
    copy.insights               = new Map();
    copy.journeys               = new Map();
    copy.journeyAccumulators    = new Map();
    copy.errorRollup            = ErrorRollup.empty();

    copy.currentSource  = { ...this.currentSource };
    copy.decodedText    = this.decodedText;
    copy.parsedRecords  = this.parsedRecords.map((r) => ({ ...r }));
    copy.mappedRecords  = this.mappedRecords.map((r) => ({ ...r }));
    copy.ingestedEvents = this.ingestedEvents.map((e) => CartographerState.cloneVariant(e));
    copy.canonical        = CartographerState.cloneVariant(this.canonical);
    copy.canonicalVariant = CartographerState.cloneVariant(this.canonicalVariant);

    copy.raw = {
      ...this.raw,
      'lineItems': this.raw.lineItems.map((li) => ({ ...li })),
    };

    copy.normalized = {
      ...this.normalized,
      'lineItems': this.normalized.lineItems.map((li) => ({ ...li })),
    };

    copy.currentEvent = { ...this.currentEvent };

    copy.geoContext = {
      ...this.geoContext,
      'countries':   [...this.geoContext.countries],
      'waterBodies': [...this.geoContext.waterBodies],
    };

    copy.pricedOrder = {
      ...this.pricedOrder,
      'lines': this.pricedOrder.lines.map((l) => ({ ...l })),
    };

    copy.shippingQuote = {
      ...this.shippingQuote,
      'breakdown': { ...this.shippingQuote.breakdown },
    };

    copy.deliveryEstimate = { ...this.deliveryEstimate };

    copy.legKm = this.legKm;
    copy.coldChainBreach = this.coldChainBreach;
    copy.customsDwellHours = this.customsDwellHours;

    copy.capturedErrors = this.capturedErrors.map((e) => ({ ...e }));
    copy.ipCandidate  = { ...this.ipCandidate };
    copy.resolvedGeo  = { ...this.resolvedGeo, 'modalities': [...this.resolvedGeo.modalities], 'provenance': [...this.resolvedGeo.provenance] };
    copy.geoSignal    = { ...this.geoSignal };
    copy.geoResolution = { ...this.geoResolution };
    copy.geoSignals    = this.geoSignals.map((s) => ({ ...s }));
    copy.candidate     = { ...this.candidate };
    copy.geoCandidates = this.geoCandidates.map((c) => ({ ...c }));

    copy.routing = { ...this.routing, 'geoModalities': [...this.routing.geoModalities] };

    copy.gdprResult = {
      ...this.gdprResult,
      'personalDataFields':  [...this.gdprResult.personalDataFields],
      'sensitiveDataFields': [...this.gdprResult.sensitiveDataFields],
      'retention': { ...this.gdprResult.retention },
    };

    copy.enriched = {
      ...this.enriched,
      'redactedSample': { ...this.enriched.redactedSample },
    };

    return copy;
  }

  protected override snapshotData(): JsonObjectType {
    return {
      'eventCount': this.eventCount,
      'eventConfig': this.eventConfig.map((e) => ({ 'eventType': e.eventType, 'count': e.count, 'formatMix': e.formatMix.map((m) => ({ 'format': m.format, 'compression': m.compression, 'weight': m.weight })) })),
      // AsyncIterable sources are not checkpointable. Resume rebuilds them via
      // CartographerSourceIntake using eventConfig + streamCount + cursor.
      // Snapshot as an empty array so restoreData leaves sources = [].
      'sources':    Array.isArray(this.sources)
        ? this.sources.map((s) => CartographerState.sourceToJson(s))
        : [],
      'useStreamingSource': this.useStreamingSource,
      'streamCount': this.streamCount,
      'streamChannelCapacity': this.streamChannelCapacity,
      'ingestBuckets': this.ingestBuckets.map((bucket) => bucket.map((e) => CartographerState.variantToJson(e))),
      'canonicalEvents': this.canonicalEvents.map((e) => CartographerState.variantToJson(e)),
      'records':      this.records.map((r) => CartographerState.enrichedToJson(r)),
      'sampleRecords': this.sampleRecords.map((r) => CartographerState.enrichedToJson(r)),
      'enriched': CartographerState.enrichedToJson(this.enriched),
      'insights': [...this.insights.entries()].map(([key, r]) => ({
        'key': key,
        'region': r.region, 'country': r.country, 'hub': r.hub,
        'deliveries': r.deliveries, 'exceptions': r.exceptions,
        'onTimeCount': r.onTimeCount, 'lateCount': r.lateCount,
        'totalSubtotalUsdMinor': r.totalSubtotalUsdMinor,
        'totalShippingUsdMinor': r.totalShippingUsdMinor,
        'totalDistanceKm': r.totalDistanceKm,
        'totalDelayHours': r.totalDelayHours,
        'consentValid': r.consentValid, 'consentMissing': r.consentMissing, 'consentExpired': r.consentExpired,
        'sizeTierEnvelope': r.sizeTierEnvelope, 'sizeTierSmall': r.sizeTierSmall,
        'sizeTierMedium': r.sizeTierMedium, 'sizeTierLarge': r.sizeTierLarge, 'sizeTierFreight': r.sizeTierFreight,
        'shipmentCount': r.shipmentCount,
      })),
      'journeyAccumulators': [...this.journeyAccumulators.entries()].map(([id, acc]) => ({
        'id': id,
        'scans': acc.scans.map((s) => ({
          'scanSeq': s.scanSeq, 'epochMs': s.epochMs, 'localIso': s.localIso,
          'utcOffset': s.utcOffset, 'timezone': s.timezone, 'jurisdiction': s.jurisdiction,
          'status': s.status, 'hub': s.hub, 'region': s.region, 'country': s.country,
          'lat': s.lat, 'lng': s.lng, 'legKm': s.legKm, 'disruptionReason': s.disruptionReason,
        })),
        'scanCount': acc.scanCount, 'pathKm': acc.pathKm,
        'minEpoch': acc.minEpoch, 'maxEpoch': acc.maxEpoch,
        'offsets': [...acc.offsets], 'timezones': [...acc.timezones], 'jurisdictions': [...acc.jurisdictions],
        'statusProgression': [...acc.statusProgression],
        'delivered': acc.delivered, 'etaCaptured': acc.etaCaptured, 'onTime': acc.onTime,
        'delayHours': acc.delayHours, 'subtotalUsdMinor': acc.subtotalUsdMinor, 'shippingUsdMinor': acc.shippingUsdMinor,
      })),
      'errorRollup': {
        'total': this.errorRollup.total,
        'groups': [...this.errorRollup.groups.entries()].map(([key, g]) => ({
          'key': key,
          'source': g.source, 'variant': g.variant, 'count': g.count,
          'samples': [...g.samples], 'sampleInput': g.sampleInput,
        })),
      },
    };
  }

  protected override restoreData(snap: JsonObjectType): void {
    if (typeof snap['eventCount'] === 'number') this.eventCount = snap['eventCount'];
    if (typeof snap['useStreamingSource'] === 'boolean') this.useStreamingSource = snap['useStreamingSource'];
    if (typeof snap['streamCount'] === 'number') this.streamCount = snap['streamCount'];
    if (typeof snap['streamChannelCapacity'] === 'number') this.streamChannelCapacity = snap['streamChannelCapacity'];
    if (Array.isArray(snap['sources'])) {
      this.sources = snap['sources'].map((s) => CartographerState.sourceFromJson(CartographerState.asObject(s) ?? {}));
    }
    if (Array.isArray(snap['ingestBuckets'])) {
      this.ingestBuckets = snap['ingestBuckets'].map((bucket) =>
        Array.isArray(bucket)
          ? bucket.map((e) => CartographerState.variantFromJson(CartographerState.asObject(e) ?? {}))
          : [],
      );
    }
    if (Array.isArray(snap['canonicalEvents'])) {
      this.canonicalEvents = snap['canonicalEvents'].map((e) => CartographerState.variantFromJson(CartographerState.asObject(e) ?? {}));
    }
    if (Array.isArray(snap['eventConfig'])) {
      const loadedEvtCfg: EventTypeConfig = snap['eventConfig']
        .map((e) => CartographerState.asObject(e))
        .filter((e): e is JsonObjectType => e !== null)
        .map((e) => {
          const mixRaw = Array.isArray(e['formatMix']) ? e['formatMix'] : [];
          const formatMix = mixRaw
            .map((m) => CartographerState.asObject(m))
            .filter((m): m is JsonObjectType => m !== null)
            .map((m): { readonly format: 'csv' | 'json' | 'ndjson' | 'yaml'; readonly compression: 'none' | 'gzip'; readonly weight: number } => ({
              'format':      CartographerState.sourceFormat(m['format']),
              'compression': m['compression'] === 'gzip' ? 'gzip' : 'none',
              'weight':      CartographerState.num(m['weight'], 1),
            }));
          return {
            'eventType': CartographerState.canonicalEventType(e['eventType']),
            'count':     CartographerState.num(e['count']),
            'formatMix': formatMix,
          };
        });
      if (loadedEvtCfg.length > 0) this.eventConfig = loadedEvtCfg;
    }
    if (Array.isArray(snap['records'])) {
      this.records = snap['records'].map((r) => CartographerState.enrichedFromJson(CartographerState.asObject(r) ?? {}));
    }
    if (Array.isArray(snap['sampleRecords'])) {
      this.sampleRecords = snap['sampleRecords'].map((r) => CartographerState.enrichedFromJson(CartographerState.asObject(r) ?? {}));
    }
    const enObj = CartographerState.asObject(snap['enriched']);
    if (enObj !== null) this.enriched = CartographerState.enrichedFromJson(enObj);
    if (Array.isArray(snap['insights'])) {
      this.insights = new Map(
        snap['insights']
          .map((e) => CartographerState.asObject(e))
          .filter((e): e is JsonObjectType => e !== null)
          .map((e): [string, RegionInsights] => [
            CartographerState.str(e['key']),
            {
              'region': CartographerState.str(e['region']),
              'country': CartographerState.str(e['country']),
              'hub': CartographerState.str(e['hub']),
              'deliveries': CartographerState.num(e['deliveries']),
              'exceptions': CartographerState.num(e['exceptions']),
              'onTimeCount': CartographerState.num(e['onTimeCount']),
              'lateCount': CartographerState.num(e['lateCount']),
              'totalSubtotalUsdMinor': CartographerState.num(e['totalSubtotalUsdMinor']),
              'totalShippingUsdMinor': CartographerState.num(e['totalShippingUsdMinor']),
              'totalDistanceKm': CartographerState.num(e['totalDistanceKm']),
              'totalDelayHours': CartographerState.num(e['totalDelayHours']),
              'consentValid': CartographerState.num(e['consentValid']),
              'consentMissing': CartographerState.num(e['consentMissing']),
              'consentExpired': CartographerState.num(e['consentExpired']),
              'sizeTierEnvelope': CartographerState.num(e['sizeTierEnvelope']),
              'sizeTierSmall': CartographerState.num(e['sizeTierSmall']),
              'sizeTierMedium': CartographerState.num(e['sizeTierMedium']),
              'sizeTierLarge': CartographerState.num(e['sizeTierLarge']),
              'sizeTierFreight': CartographerState.num(e['sizeTierFreight']),
              'shipmentCount': CartographerState.num(e['shipmentCount']),
            },
          ])
      );
    }
    if (Array.isArray(snap['journeyAccumulators'])) {
      this.journeyAccumulators = new Map(
        snap['journeyAccumulators']
          .map((e) => CartographerState.asObject(e))
          .filter((e): e is JsonObjectType => e !== null)
          .map((e): [string, JourneyAccumulator] => [
            CartographerState.str(e['id']),
            {
              'scans': Array.isArray(e['scans'])
                ? e['scans']
                    .map((s) => CartographerState.asObject(s))
                    .filter((s): s is JsonObjectType => s !== null)
                    .map((s): JourneyScan => ({
                      'scanSeq': CartographerState.num(s['scanSeq']),
                      'epochMs': CartographerState.num(s['epochMs']),
                      'localIso': CartographerState.str(s['localIso']),
                      'utcOffset': CartographerState.str(s['utcOffset']),
                      'timezone': CartographerState.str(s['timezone']),
                      'jurisdiction': CartographerState.str(s['jurisdiction']),
                      'status': CartographerState.str(s['status']),
                      'hub': CartographerState.str(s['hub']),
                      'region': CartographerState.str(s['region']),
                      'country': CartographerState.str(s['country']),
                      'lat': CartographerState.num(s['lat']),
                      'lng': CartographerState.num(s['lng']),
                      'legKm': CartographerState.num(s['legKm']),
                      'disruptionReason': CartographerState.str(s['disruptionReason']),
                    }))
                : [],
              'scanCount': CartographerState.num(e['scanCount']),
              'pathKm': CartographerState.num(e['pathKm']),
              'minEpoch': CartographerState.num(e['minEpoch']),
              'maxEpoch': CartographerState.num(e['maxEpoch']),
              'offsets': CartographerState.strArr(e['offsets']),
              'timezones': CartographerState.strArr(e['timezones']),
              'jurisdictions': CartographerState.strArr(e['jurisdictions']),
              'statusProgression': CartographerState.strArr(e['statusProgression']),
              'delivered': CartographerState.bool(e['delivered']),
              'etaCaptured': CartographerState.bool(e['etaCaptured']),
              'onTime': CartographerState.bool(e['onTime']),
              'delayHours': CartographerState.num(e['delayHours']),
              'subtotalUsdMinor': CartographerState.num(e['subtotalUsdMinor']),
              'shippingUsdMinor': CartographerState.num(e['shippingUsdMinor']),
            },
          ])
      );
    }
    const rollupRaw = CartographerState.asObject(snap['errorRollup']);
    if (rollupRaw !== null) {
      const groupsRaw = Array.isArray(rollupRaw['groups']) ? rollupRaw['groups'] : [];
      const groups = new Map<string, ErrorGroupType>(
        groupsRaw
          .map((g) => CartographerState.asObject(g))
          .filter((g): g is JsonObjectType => g !== null)
          .map((g): [string, ErrorGroupType] => [
            CartographerState.str(g['key']),
            {
              'source': CartographerState.str(g['source']),
              'variant': CartographerState.str(g['variant']),
              'count': CartographerState.num(g['count']),
              'samples': CartographerState.strArr(g['samples']),
              'sampleInput': CartographerState.str(g['sampleInput']),
            },
          ])
      );
      this.errorRollup = { 'total': CartographerState.num(rollupRaw['total']), 'groups': groups };
    }
  }

  // ── Scalar narrowing helpers (no blanket `as unknown as` casts) ────────────

  /** Type predicate: narrows `unknown` to `JsonObjectType` via structural runtime checks. */
  private static isJsonObject(value: unknown): value is JsonObjectType {
    return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
  }

  private static asObject(value: unknown): JsonObjectType | null {
    return CartographerState.isJsonObject(value) ? value : null;
  }

  private static str(value: unknown, defaultValue: string = ''): string {
    return typeof value === 'string' ? value : defaultValue;
  }

  private static num(value: unknown, defaultValue: number = 0): number {
    return typeof value === 'number' ? value : defaultValue;
  }

  private static bool(value: unknown, defaultValue: boolean = false): boolean {
    return typeof value === 'boolean' ? value : defaultValue;
  }

  private static strArr(value: unknown): string[] {
    return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];
  }

  // ── CanonicalEventVariant / SourcePayload narrowers + reconstruction ──────────────
  private static canonicalEventType(value: unknown): CanonicalEventVariant['eventType'] {
    return value === 'position-ping' || value === 'facility-scan' || value === 'sensor-reading'
      || value === 'customs-event' || value === 'delivery-confirmation'
      ? value
      : 'position-ping';
  }

  private static sourceFormat(value: unknown): SourcePayload['format'] {
    return value === 'csv' || value === 'json' || value === 'ndjson' || value === 'yaml' ? value : 'json';
  }

  private static canonicalSourceFormat(value: unknown): CanonicalEventVariant['sourceFormat'] {
    return value === 'csv' || value === 'json' || value === 'ndjson' || value === 'yaml' ? value : 'json';
  }

  private static canonicalSourceCompression(value: unknown): CanonicalEventVariant['sourceCompression'] {
    return value === 'none' || value === 'gzip' ? value : 'none';
  }

  // ── Dispatch maps (replace switches on eventType) ──────────────────────────

  private static readonly cloneVariantDispatch: Readonly<Record<string, (v: CanonicalEventVariant) => CanonicalEventVariant>> = {
    'position-ping': (v) => {
      if (v.eventType !== 'position-ping') return v;
      const copy: PositionPingEvent = { ...CartographerState.variantEnvelope(v), 'eventType': 'position-ping', 'body': { ...v.body } };
      if (v.geo !== undefined) copy.geo = { ...v.geo };
      if (v.consentHandled !== undefined) copy.consentHandled = v.consentHandled;
      if (v.pii !== undefined) copy.pii = v.pii;
      return copy;
    },
    'facility-scan': (v) => {
      if (v.eventType !== 'facility-scan') return v;
      const copy: FacilityScanEvent = { ...CartographerState.variantEnvelope(v), 'eventType': 'facility-scan', 'body': { ...v.body, 'lineItems': v.body.lineItems.map((li) => ({ ...li })) } };
      if (v.geo !== undefined) copy.geo = { ...v.geo };
      if (v.consentHandled !== undefined) copy.consentHandled = v.consentHandled;
      if (v.pii !== undefined) copy.pii = v.pii;
      return copy;
    },
    'sensor-reading': (v) => {
      if (v.eventType !== 'sensor-reading') return v;
      const copy: SensorReadingEvent = { ...CartographerState.variantEnvelope(v), 'eventType': 'sensor-reading', 'body': { ...v.body } };
      if (v.geo !== undefined) copy.geo = { ...v.geo };
      if (v.consentHandled !== undefined) copy.consentHandled = v.consentHandled;
      if (v.pii !== undefined) copy.pii = v.pii;
      return copy;
    },
    'customs-event': (v) => {
      if (v.eventType !== 'customs-event') return v;
      const copy: CustomsEvent = { ...CartographerState.variantEnvelope(v), 'eventType': 'customs-event', 'body': { ...v.body } };
      if (v.geo !== undefined) copy.geo = { ...v.geo };
      if (v.consentHandled !== undefined) copy.consentHandled = v.consentHandled;
      if (v.pii !== undefined) copy.pii = v.pii;
      return copy;
    },
    'delivery-confirmation': (v) => {
      if (v.eventType !== 'delivery-confirmation') return v;
      const copy: DeliveryConfirmationEvent = { ...CartographerState.variantEnvelope(v), 'eventType': 'delivery-confirmation', 'body': { ...v.body } };
      if (v.geo !== undefined) copy.geo = { ...v.geo };
      if (v.consentHandled !== undefined) copy.consentHandled = v.consentHandled;
      if (v.pii !== undefined) copy.pii = v.pii;
      return copy;
    },
  };

  private static readonly variantToJsonBodyDispatch: Readonly<Record<string, (v: CanonicalEventVariant) => JsonObjectType>> = {
    'position-ping': (v) => {
      if (v.eventType !== 'position-ping') return {};
      return {
        'scanSeq':      v.body.scanSeq,   'latitude':   v.body.latitude,  'longitude':    v.body.longitude,
        'ipAddress':    v.body.ipAddress,  'localeTag':  v.body.localeTag,  'countryCode':  v.body.countryCode,
        'legFromLat': v.body.legFromLat, 'legFromLng':  v.body.legFromLng,
        'originLat':    v.body.originLat,  'originLng':  v.body.originLng,  'destLat':     v.body.destLat,  'destLng': v.body.destLng,
        'carrier':      v.body.carrier,    'status':     v.body.status,      'rawTimestamp': v.body.rawTimestamp,
        'address': v.body.address, 'phone': v.body.phone,
      };
    },
    'facility-scan': (v) => {
      if (v.eventType !== 'facility-scan') return {};
      return {
        'scanSeq':      v.body.scanSeq,   'latitude':   v.body.latitude,  'longitude':    v.body.longitude,
        'ipAddress':    v.body.ipAddress,  'localeTag':  v.body.localeTag,  'countryCode':  v.body.countryCode,
        'legFromLat': v.body.legFromLat, 'legFromLng':  v.body.legFromLng,
        'originLat':    v.body.originLat,  'originLng':  v.body.originLng,  'destLat':     v.body.destLat,  'destLng': v.body.destLng,
        'carrier':      v.body.carrier,    'status':     v.body.status,      'rawTimestamp': v.body.rawTimestamp,
        'facilityId':   v.body.facilityId, 'weight': v.body.weight, 'weightUnit': v.body.weightUnit,
        'lineItems':    v.body.lineItems.map((li) => ({ 'productId': li.productId, 'quantity': li.quantity })),
        'rawDispatchAt': v.body.rawDispatchAt, 'rawPromisedDeliveryAt': v.body.rawPromisedDeliveryAt,
        'disruptionReason': v.body.disruptionReason,
        'recipientName': v.body.recipientName, 'recipientEmail': v.body.recipientEmail,
        'recipientPhone': v.body.recipientPhone, 'recipientAddress': v.body.recipientAddress,
        'recipientCountry': v.body.recipientCountry, 'marketingConsent': v.body.marketingConsent,
        'lawfulBasis':  v.body.lawfulBasis, 'specialCategory': v.body.specialCategory,
        'address': v.body.address, 'phone': v.body.phone,
      };
    },
    'sensor-reading': (v) => {
      if (v.eventType !== 'sensor-reading') return {};
      return {
        'scanSeq':      v.body.scanSeq,   'latitude':   v.body.latitude,  'longitude':    v.body.longitude,
        'ipAddress':    v.body.ipAddress,  'localeTag':  v.body.localeTag,  'countryCode':  v.body.countryCode,
        'legFromLat': v.body.legFromLat, 'legFromLng':  v.body.legFromLng,
        'originLat':    v.body.originLat,  'originLng':  v.body.originLng,  'destLat':     v.body.destLat,  'destLng': v.body.destLng,
        'carrier':      v.body.carrier,    'status':     v.body.status,      'rawTimestamp': v.body.rawTimestamp,
        'tempC':        v.body.tempC,      'humidityPct': v.body.humidityPct, 'shockG': v.body.shockG,
        'address': v.body.address, 'phone': v.body.phone,
      };
    },
    'customs-event': (v) => {
      if (v.eventType !== 'customs-event') return {};
      return {
        'scanSeq':      v.body.scanSeq,   'latitude':   v.body.latitude,  'longitude':    v.body.longitude,
        'ipAddress':    v.body.ipAddress,  'localeTag':  v.body.localeTag,  'countryCode':  v.body.countryCode,
        'legFromLat': v.body.legFromLat, 'legFromLng':  v.body.legFromLng,
        'originLat':    v.body.originLat,  'originLng':  v.body.originLng,  'destLat':     v.body.destLat,  'destLng': v.body.destLng,
        'carrier':      v.body.carrier,    'status':     v.body.status,      'rawTimestamp': v.body.rawTimestamp,
        'customsStatus': v.body.customsStatus,
        'address': v.body.address, 'phone': v.body.phone,
      };
    },
    'delivery-confirmation': (v) => {
      if (v.eventType !== 'delivery-confirmation') return {};
      return {
        'scanSeq':      v.body.scanSeq,   'latitude':   v.body.latitude,  'longitude':    v.body.longitude,
        'ipAddress':    v.body.ipAddress,  'localeTag':  v.body.localeTag,  'countryCode':  v.body.countryCode,
        'legFromLat': v.body.legFromLat, 'legFromLng':  v.body.legFromLng,
        'originLat':    v.body.originLat,  'originLng':  v.body.originLng,  'destLat':     v.body.destLat,  'destLng': v.body.destLng,
        'carrier':      v.body.carrier,    'status':     v.body.status,      'rawTimestamp': v.body.rawTimestamp,
        'delivered':    v.body.delivered,  'rawPromisedDeliveryAt': v.body.rawPromisedDeliveryAt,
        'disruptionReason': v.body.disruptionReason,
        'recipientName': v.body.recipientName, 'recipientEmail': v.body.recipientEmail,
        'recipientPhone': v.body.recipientPhone, 'recipientAddress': v.body.recipientAddress,
        'recipientCountry': v.body.recipientCountry, 'marketingConsent': v.body.marketingConsent,
        'lawfulBasis':  v.body.lawfulBasis, 'specialCategory': v.body.specialCategory,
        'address': v.body.address, 'phone': v.body.phone,
      };
    },
  };

  private static readonly variantFromJsonDispatch: Readonly<Record<string, (
    envelope: { shipmentId: string; eventId: string; epochMs: number; sourceId: string; sourceFormat: CanonicalEventVariant['sourceFormat']; sourceCompression: CanonicalEventVariant['sourceCompression'] },
    sharedBody: { scanSeq: number; latitude: number; longitude: number; ipAddress: string; localeTag: string; countryCode: string; legFromLat: number; legFromLng: number; originLat: number; originLng: number; destLat: number; destLng: number; carrier: string; status: string; rawTimestamp: string; address: string; phone: string },
    b: Record<string, unknown>,
    o: Record<string, unknown>,
  ) => CanonicalEventVariant>> = {
    'facility-scan': (envelope, sharedBody, b, o) => {
      const variant: FacilityScanEvent = {
        ...envelope, 'eventType': 'facility-scan',
        'body': {
          ...sharedBody,
          'facilityId':           CartographerState.str(b['facilityId']),
          'weight':               CartographerState.num(b['weight']),
          'weightUnit':           CartographerState.weightUnit(b['weightUnit']),
          'lineItems':            CartographerState.lineItemsFromJson(b['lineItems']),
          'rawDispatchAt':        CartographerState.str(b['rawDispatchAt']),
          'rawPromisedDeliveryAt': CartographerState.str(b['rawPromisedDeliveryAt']),
          'disruptionReason':     CartographerState.str(b['disruptionReason']),
          'recipientName':        CartographerState.str(b['recipientName']),
          'recipientEmail':       CartographerState.str(b['recipientEmail']),
          'recipientPhone':       CartographerState.str(b['recipientPhone']),
          'recipientAddress':     CartographerState.str(b['recipientAddress']),
          'recipientCountry':     CartographerState.str(b['recipientCountry']),
          'marketingConsent':     CartographerState.bool(b['marketingConsent']),
          'lawfulBasis':          CartographerState.lawfulBasis(b['lawfulBasis']),
          'specialCategory':      CartographerState.specialCategory(b['specialCategory']),
        },
      };
      const geoObj = CartographerState.asObject(o['geo']);
      if (geoObj !== null) variant.geo = { 'country': CartographerState.str(geoObj['country']), 'continent': CartographerState.str(geoObj['continent']), 'region': CartographerState.str(geoObj['region']) };
      if (typeof o['consentHandled'] === 'boolean') variant.consentHandled = o['consentHandled'];
      if (typeof o['pii'] === 'boolean') variant.pii = o['pii'];
      return variant;
    },
    'sensor-reading': (envelope, sharedBody, b, o) => {
      const variant: SensorReadingEvent = {
        ...envelope, 'eventType': 'sensor-reading',
        'body': {
          ...sharedBody,
          'tempC':       CartographerState.num(b['tempC']),
          'humidityPct': CartographerState.num(b['humidityPct']),
          'shockG':      CartographerState.num(b['shockG']),
        },
      };
      const geoObj = CartographerState.asObject(o['geo']);
      if (geoObj !== null) variant.geo = { 'country': CartographerState.str(geoObj['country']), 'continent': CartographerState.str(geoObj['continent']), 'region': CartographerState.str(geoObj['region']) };
      if (typeof o['consentHandled'] === 'boolean') variant.consentHandled = o['consentHandled'];
      if (typeof o['pii'] === 'boolean') variant.pii = o['pii'];
      return variant;
    },
    'customs-event': (envelope, sharedBody, b, o) => {
      const variant: CustomsEvent = {
        ...envelope, 'eventType': 'customs-event',
        'body': { ...sharedBody, 'customsStatus': CartographerState.str(b['customsStatus']) },
      };
      const geoObj = CartographerState.asObject(o['geo']);
      if (geoObj !== null) variant.geo = { 'country': CartographerState.str(geoObj['country']), 'continent': CartographerState.str(geoObj['continent']), 'region': CartographerState.str(geoObj['region']) };
      if (typeof o['consentHandled'] === 'boolean') variant.consentHandled = o['consentHandled'];
      if (typeof o['pii'] === 'boolean') variant.pii = o['pii'];
      return variant;
    },
    'delivery-confirmation': (envelope, sharedBody, b, o) => {
      const variant: DeliveryConfirmationEvent = {
        ...envelope, 'eventType': 'delivery-confirmation',
        'body': {
          ...sharedBody,
          'delivered':             CartographerState.bool(b['delivered']),
          'rawPromisedDeliveryAt': CartographerState.str(b['rawPromisedDeliveryAt']),
          'disruptionReason':      CartographerState.str(b['disruptionReason']),
          'recipientName':         CartographerState.str(b['recipientName']),
          'recipientEmail':        CartographerState.str(b['recipientEmail']),
          'recipientPhone':        CartographerState.str(b['recipientPhone']),
          'recipientAddress':      CartographerState.str(b['recipientAddress']),
          'recipientCountry':      CartographerState.str(b['recipientCountry']),
          'marketingConsent':      CartographerState.bool(b['marketingConsent']),
          'lawfulBasis':           CartographerState.lawfulBasis(b['lawfulBasis']),
          'specialCategory':       CartographerState.specialCategory(b['specialCategory']),
        },
      };
      const geoObj = CartographerState.asObject(o['geo']);
      if (geoObj !== null) variant.geo = { 'country': CartographerState.str(geoObj['country']), 'continent': CartographerState.str(geoObj['continent']), 'region': CartographerState.str(geoObj['region']) };
      if (typeof o['consentHandled'] === 'boolean') variant.consentHandled = o['consentHandled'];
      if (typeof o['pii'] === 'boolean') variant.pii = o['pii'];
      return variant;
    },
    'position-ping': (envelope, sharedBody, _b, o) => {
      const variant: PositionPingEvent = { ...envelope, 'eventType': 'position-ping', 'body': { ...sharedBody } };
      const geoObj = CartographerState.asObject(o['geo']);
      if (geoObj !== null) variant.geo = { 'country': CartographerState.str(geoObj['country']), 'continent': CartographerState.str(geoObj['continent']), 'region': CartographerState.str(geoObj['region']) };
      if (typeof o['consentHandled'] === 'boolean') variant.consentHandled = o['consentHandled'];
      if (typeof o['pii'] === 'boolean') variant.pii = o['pii'];
      return variant;
    },
  };

  /** Extract the shared envelope fields from a CanonicalEventVariant (used by dispatch maps). */
  private static variantEnvelope(v: CanonicalEventVariant): {
    shipmentId: string; eventId: string; epochMs: number;
    sourceId: string; sourceFormat: CanonicalEventVariant['sourceFormat']; sourceCompression: CanonicalEventVariant['sourceCompression'];
  } {
    return {
      'shipmentId':        v.shipmentId,
      'eventId':           v.eventId,
      'epochMs':           v.epochMs,
      'sourceId':          v.sourceId,
      'sourceFormat':      v.sourceFormat,
      'sourceCompression': v.sourceCompression,
    };
  }

  private static resolveCloneHandler(eventType: string): (v: CanonicalEventVariant) => CanonicalEventVariant {
    return CartographerState.cloneVariantDispatch[eventType]
        ?? CartographerState.cloneVariantDispatch['position-ping']
        ?? ((vv: CanonicalEventVariant): CanonicalEventVariant => ({ ...vv }));
  }

  /** Deep-clone a CanonicalEventVariant (dispatch map on eventType to keep each member's exact shape). */
  private static cloneVariant(v: CanonicalEventVariant): CanonicalEventVariant {
    return CartographerState.resolveCloneHandler(v.eventType)(v);
  }

  private static resolveToJsonBodyHandler(eventType: string): (v: CanonicalEventVariant) => JsonObjectType {
    return CartographerState.variantToJsonBodyDispatch[eventType]
        ?? CartographerState.variantToJsonBodyDispatch['position-ping']
        ?? (() => ({}));
  }

  /** Serialize a CanonicalEventVariant to a JSON-safe object (dispatch map on eventType for exact body fields). */
  private static variantToJson(v: CanonicalEventVariant): JsonObjectType {
    const bodyHandler = CartographerState.resolveToJsonBodyHandler(v.eventType);
    return {
      'shipmentId':        v.shipmentId,
      'eventId':           v.eventId,
      'epochMs':           v.epochMs,
      'eventType':         v.eventType,
      'sourceId':          v.sourceId,
      'sourceFormat':      v.sourceFormat,
      'sourceCompression': v.sourceCompression,
      'geo':               v.geo !== undefined ? { 'country': v.geo.country, 'continent': v.geo.continent, 'region': v.geo.region } : null,
      'consentHandled':    v.consentHandled !== undefined ? v.consentHandled : null,
      'pii':               v.pii !== undefined ? v.pii : null,
      'body':              bodyHandler(v),
    };
  }

  private static resolveFromJsonHandler(eventType: string): (
    envelope: { shipmentId: string; eventId: string; epochMs: number; sourceId: string; sourceFormat: CanonicalEventVariant['sourceFormat']; sourceCompression: CanonicalEventVariant['sourceCompression'] },
    sharedBody: { scanSeq: number; latitude: number; longitude: number; ipAddress: string; localeTag: string; countryCode: string; legFromLat: number; legFromLng: number; originLat: number; originLng: number; destLat: number; destLng: number; carrier: string; status: string; rawTimestamp: string; address: string; phone: string },
    b: Record<string, unknown>,
    o: Record<string, unknown>,
  ) => CanonicalEventVariant {
    const pp = (
      envelope: { shipmentId: string; eventId: string; epochMs: number; sourceId: string; sourceFormat: CanonicalEventVariant['sourceFormat']; sourceCompression: CanonicalEventVariant['sourceCompression'] },
      sharedBody: { scanSeq: number; latitude: number; longitude: number; ipAddress: string; localeTag: string; countryCode: string; legFromLat: number; legFromLng: number; originLat: number; originLng: number; destLat: number; destLng: number; carrier: string; status: string; rawTimestamp: string; address: string; phone: string },
      _b: Record<string, unknown>,
      o: Record<string, unknown>,
    ): CanonicalEventVariant => {
      const variant: PositionPingEvent = { ...envelope, 'eventType': 'position-ping', 'body': { ...sharedBody } };
      const geoObj = CartographerState.asObject(o['geo']);
      if (geoObj !== null) variant.geo = { 'country': CartographerState.str(geoObj['country']), 'continent': CartographerState.str(geoObj['continent']), 'region': CartographerState.str(geoObj['region']) };
      if (typeof o['consentHandled'] === 'boolean') variant.consentHandled = o['consentHandled'];
      if (typeof o['pii'] === 'boolean') variant.pii = o['pii'];
      return variant;
    };
    return CartographerState.variantFromJsonDispatch[eventType] ?? pp;
  }

  /** Reconstruct a CanonicalEventVariant from a deserialized JSON object (dispatch map on eventType). */
  private static variantFromJson(o: Record<string, unknown>): CanonicalEventVariant {
    const eventType = typeof o['eventType'] === 'string' ? o['eventType'] : 'position-ping';
    const b = CartographerState.asObject(o['body']) ?? {};
    const envelope = {
      'shipmentId':        CartographerState.str(o['shipmentId']),
      'eventId':           CartographerState.str(o['eventId']),
      'epochMs':           CartographerState.num(o['epochMs']),
      'sourceId':          CartographerState.str(o['sourceId']),
      'sourceFormat':      CartographerState.canonicalSourceFormat(o['sourceFormat']),
      'sourceCompression': CartographerState.canonicalSourceCompression(o['sourceCompression']),
    };
    const sharedBody = {
      'scanSeq':      CartographerState.num(b['scanSeq']),
      'latitude':     CartographerState.num(b['latitude']),
      'longitude':    CartographerState.num(b['longitude']),
      'ipAddress':    CartographerState.str(b['ipAddress']),
      'localeTag':    CartographerState.str(b['localeTag']),
      'countryCode':  CartographerState.str(b['countryCode']),
      'legFromLat':   CartographerState.num(b['legFromLat']),
      'legFromLng':   CartographerState.num(b['legFromLng']),
      'originLat':    CartographerState.num(b['originLat']),
      'originLng':    CartographerState.num(b['originLng']),
      'destLat':      CartographerState.num(b['destLat']),
      'destLng':      CartographerState.num(b['destLng']),
      'carrier':      CartographerState.str(b['carrier']),
      'status':       CartographerState.str(b['status']),
      'rawTimestamp': CartographerState.str(b['rawTimestamp']),
      'address':      CartographerState.str(b['address']),
      'phone':        CartographerState.str(b['phone']),
    };
    return CartographerState.resolveFromJsonHandler(eventType)(envelope, sharedBody, b, o);
  }

  private static sourceToJson(s: SourcePayload): JsonObjectType {
    return {
      'sourceId':    s.sourceId,
      'format':      s.format,
      'compression': s.compression,
      'mappingKey':  s.mappingKey,
      'eventType':   s.eventType,
      'payload':     s.payload,
    };
  }

  private static sourceFromJson(o: Record<string, unknown>): SourcePayload {
    return {
      'sourceId':    CartographerState.str(o['sourceId']),
      'format':      CartographerState.sourceFormat(o['format']),
      'compression': (o['compression'] === 'none' || o['compression'] === 'gzip') ? o['compression'] : 'none',
      'mappingKey':  CartographerState.str(o['mappingKey'], 'json-position'),
      'eventType':   CartographerState.canonicalEventType(o['eventType']),
      'payload':     CartographerState.str(o['payload']),
    };
  }

  private static geoStatus(value: unknown): GeoContext['status'] {
    return value === 'land' || value === 'water' || value === 'coastal' || value === 'unmapped'
      ? value
      : 'unmapped';
  }

  private static consentStatus(value: unknown): GdprResult['consentStatus'] {
    return value === 'valid' || value === 'missing' || value === 'expired' ? value : 'missing';
  }

  private static lawfulBasis(value: unknown): GdprResult['lawfulBasis'] {
    return value === 'contract' || value === 'consent' || value === 'legitimate-interest' || value === 'none'
      ? value
      : 'contract';
  }

  private static jurisdiction(value: unknown): GeoContext['jurisdiction'] {
    return value === 'GDPR' || value === 'UK-GDPR' || value === 'CCPA'
      || value === 'LGPD' || value === 'APPI' || value === 'baseline'
      || value === 'international-waters'
      ? value
      : 'baseline';
  }

  private static lifecycleStatus(value: unknown): NormalizedShipment['status'] {
    return value === 'SCAN' || value === 'DEPARTURE' || value === 'ARRIVAL'
      || value === 'OUT_FOR_DELIVERY' || value === 'DELIVERED' || value === 'EXCEPTION'
      ? value
      : 'SCAN';
  }

  private static serviceTier(value: unknown): NormalizedShipment['serviceTier'] {
    return value === 'express' || value === 'standard' || value === 'economy' ? value : 'standard';
  }

  private static sizeTier(value: unknown): NormalizedShipment['sizeTier'] {
    return value === 'envelope' || value === 'small' || value === 'medium'
      || value === 'large' || value === 'freight'
      ? value
      : 'small';
  }

  private static weightUnit(value: unknown): RawShipmentEvent['weightUnit'] {
    return value === 'lb' || value === 'kg' || value === 'g' || value === 'oz' ? value : 'kg';
  }

  private static specialCategory(value: unknown): RawShipmentEvent['specialCategory'] {
    return value === 'none' || value === 'health' ? value : 'none';
  }

  private static lineItemsFromJson(value: unknown): Array<{ 'productId': string; 'quantity': number }> {
    if (!Array.isArray(value)) return [{ 'productId': '', 'quantity': 1 }];
    const items = value
      .map((li) => CartographerState.asObject(li))
      .filter((li): li is JsonObjectType => li !== null)
      .map((li) => ({
        'productId': CartographerState.str(li['productId']),
        'quantity':  CartographerState.num(li['quantity'], 1),
      }));
    return items.length > 0 ? items : [{ 'productId': '', 'quantity': 1 }];
  }

  // ── Entity ↔ JSON reconstruction (field-by-field) ──────────────────────────
  private static enrichedToJson(e: EnrichedShipment): JsonObjectType {
    return {
      'shipmentId': e.shipmentId, 'scanSeq': e.scanSeq, 'epochMs': e.epochMs,
      'localIso': e.localIso, 'utcOffset': e.utcOffset, 'timezone': e.timezone, 'jurisdiction': e.jurisdiction,
      'continent': e.continent, 'region': e.region, 'country': e.country, 'hub': e.hub, 'geoStatus': e.geoStatus,
      'lat': e.lat, 'lng': e.lng, 'coordsCoarsened': e.coordsCoarsened, 'legKm': e.legKm,
      'status': e.status, 'serviceTier': e.serviceTier, 'sizeTier': e.sizeTier,
      'onTime': e.onTime, 'exception': e.exception, 'consentStatus': e.consentStatus,
      'disruptionReason': e.disruptionReason,
      'subtotalUsdMinor': e.subtotalUsdMinor, 'currency': e.currency,
      'shippingUsdMinor': e.shippingUsdMinor, 'distanceKm': e.distanceKm,
      'transitHours': e.transitHours, 'delayHours': e.delayHours,
      'redactionApplied': e.redactionApplied,
      'redactedSample': {
        'recipientName': e.redactedSample.recipientName,
        'recipientEmail': e.redactedSample.recipientEmail,
        'recipientPhone': e.redactedSample.recipientPhone,
      },
      'routing': CartographerState.routingToJson(e.routing),
    };
  }

  /** The all-false default routing record (single source of truth). */
  static defaultRouting(): EnrichedShipment['routing'] {
    return {
      'path':              'order',
      'geoLookupRun':      false,
      'geoLookupSkipped':  false,
      'ipGeolocateRun':    false,
      'ipGeolocateSkipped': false,
      'geoConfidence':     0,
      'geoModalities':     [],
      'geoSourceModel':    '',
      'geoSecondaryLookupUsed': false,
      'redactionRun':      false,
      'redactionSkipped':  false,
      'pricingRun':        false,
      'pricingSkipped':    false,
      'etaRun':            false,
      'etaSkipped':        false,
      'coldChainRun':      false,
      'customsDwellRun':   false,
    };
  }

  /** An unresolved GeoCandidate for the given modality (the default). */
  static unresolvedCandidate(modality: 'gps' | 'ip'): GeoCandidate {
    return {
      'modality': modality, 'resolved': false, 'country': '', 'countryName': '',
      'continent': '', 'region': '', 'locality': '', 'lat': 0, 'lng': 0, 'water': false,
    };
  }

  private static routingToJson(r: EnrichedShipment['routing']): JsonObjectType {
    return {
      'path':              r.path,
      'geoLookupRun':      r.geoLookupRun,
      'geoLookupSkipped':  r.geoLookupSkipped,
      'ipGeolocateRun':    r.ipGeolocateRun,
      'ipGeolocateSkipped': r.ipGeolocateSkipped,
      'geoConfidence':     r.geoConfidence,
      'geoModalities':     [...r.geoModalities],
      'geoSourceModel':    r.geoSourceModel,
      'geoSecondaryLookupUsed': r.geoSecondaryLookupUsed,
      'redactionRun':      r.redactionRun,
      'redactionSkipped':  r.redactionSkipped,
      'pricingRun':        r.pricingRun,
      'pricingSkipped':    r.pricingSkipped,
      'etaRun':            r.etaRun,
      'etaSkipped':        r.etaSkipped,
      'coldChainRun':      r.coldChainRun,
      'customsDwellRun':   r.customsDwellRun,
    };
  }

  private static routingPath(value: unknown): EnrichedShipment['routing']['path'] {
    return value === 'geo-only' || value === 'sensor' || value === 'order' || value === 'customs'
      ? value
      : 'order';
  }

  private static routingFromJson(value: unknown): EnrichedShipment['routing'] {
    const o = CartographerState.asObject(value) ?? {};
    return {
      'path':              CartographerState.routingPath(o['path']),
      'geoLookupRun':      CartographerState.bool(o['geoLookupRun']),
      'geoLookupSkipped':  CartographerState.bool(o['geoLookupSkipped']),
      'ipGeolocateRun':    CartographerState.bool(o['ipGeolocateRun']),
      'ipGeolocateSkipped': CartographerState.bool(o['ipGeolocateSkipped']),
      'geoConfidence':     CartographerState.num(o['geoConfidence']),
      'geoModalities':     CartographerState.strArr(o['geoModalities']),
      'geoSourceModel':    CartographerState.str(o['geoSourceModel']),
      'geoSecondaryLookupUsed': CartographerState.bool(o['geoSecondaryLookupUsed']),
      'redactionRun':      CartographerState.bool(o['redactionRun']),
      'redactionSkipped':  CartographerState.bool(o['redactionSkipped']),
      'pricingRun':        CartographerState.bool(o['pricingRun']),
      'pricingSkipped':    CartographerState.bool(o['pricingSkipped']),
      'etaRun':            CartographerState.bool(o['etaRun']),
      'etaSkipped':        CartographerState.bool(o['etaSkipped']),
      'coldChainRun':      CartographerState.bool(o['coldChainRun']),
      'customsDwellRun':   CartographerState.bool(o['customsDwellRun']),
    };
  }

  private static enrichedFromJson(o: Record<string, unknown>): EnrichedShipment {
    const sample = CartographerState.asObject(o['redactedSample']) ?? {};
    return {
      'shipmentId': CartographerState.str(o['shipmentId']),
      'scanSeq': CartographerState.num(o['scanSeq']),
      'epochMs': CartographerState.num(o['epochMs']),
      'localIso': CartographerState.str(o['localIso']),
      'utcOffset': CartographerState.str(o['utcOffset']),
      'timezone': CartographerState.str(o['timezone'], 'UTC'),
      'jurisdiction': CartographerState.jurisdiction(o['jurisdiction']),
      'continent': CartographerState.str(o['continent'], 'Unmapped'),
      'region': CartographerState.str(o['region']),
      'country': CartographerState.str(o['country']),
      'hub': CartographerState.str(o['hub']),
      'geoStatus': CartographerState.geoStatus(o['geoStatus']),
      'lat': CartographerState.num(o['lat']),
      'lng': CartographerState.num(o['lng']),
      'coordsCoarsened': CartographerState.bool(o['coordsCoarsened']),
      'legKm': CartographerState.num(o['legKm']),
      'status': CartographerState.lifecycleStatus(o['status']),
      'serviceTier': CartographerState.serviceTier(o['serviceTier']),
      'sizeTier': CartographerState.sizeTier(o['sizeTier']),
      'onTime': CartographerState.bool(o['onTime']),
      'exception': CartographerState.bool(o['exception']),
      'consentStatus': CartographerState.consentStatus(o['consentStatus']),
      'disruptionReason': CartographerState.str(o['disruptionReason']),
      'subtotalUsdMinor': CartographerState.num(o['subtotalUsdMinor']),
      'currency': CartographerState.str(o['currency'], 'USD'),
      'shippingUsdMinor': CartographerState.num(o['shippingUsdMinor']),
      'distanceKm': CartographerState.num(o['distanceKm']),
      'transitHours': CartographerState.num(o['transitHours']),
      'delayHours': CartographerState.num(o['delayHours']),
      'redactionApplied': CartographerState.bool(o['redactionApplied']),
      'redactedSample': {
        'recipientName': CartographerState.str(sample['recipientName']),
        'recipientEmail': CartographerState.str(sample['recipientEmail']),
        'recipientPhone': CartographerState.str(sample['recipientPhone']),
      },
      'routing': CartographerState.routingFromJson(o['routing']),
    };
  }
}

CartographerServices

The dependency record passed into node constructors. Services carry two transport adapters: ipGeolocator (live freeipapi.com or committed fixture replay) and addressGeocoder (live OpenStreetMap Nominatim or deterministic no-answer in the smoke). Coords, locale, code, and phone resolution are fully offline — GeohashTzMap, CoordTimezone, and CallingCode need no injected transport.

ts
export interface CartographerServices {
  /** IP-modality transport (geolocate gateway IP → place). */
  readonly ipGeolocator: IpGeolocator;
  /** Address-modality transport (forward-geocode postal address → place). */
  readonly addressGeocoder: AddressGeocoder;
}

GeoResolvers

Factory that assembles the CartographerServices record for the chosen backend.

ts
export class GeoResolvers {
  /** Live services: live freeipapi IP geolocation and Nominatim address geocoding. */
  static live(): CartographerServices {
    return {
      'ipGeolocator':    new LiveIpGeolocator(),
      'addressGeocoder': new LiveAddressGeocoder(),
    };
  }

  /** Recorded services: fixture-replay IP geolocation and deterministic address geocoding.
   *  Deterministic and offline — used by the smoke and `--recorded` CLI flag. */
  static recorded(): CartographerServices {
    return {
      'ipGeolocator':    new RecordedIpGeolocator(),
      'addressGeocoder': new RecordedAddressGeocoder(),
    };
  }
}

Key nodes

sourceIntake — multi-entry gather intake

Each data-type entrypoint targets intake-gather directly. The scheduler seeds one gather record per entrypoint label; the source-intake gather opens those per-type streams and merges them into state.sources. There is no seed pre-phase, no pre-node, and no scatter before the gather.

ts
/**
 * sourceIntake: stream construction helpers for Cartographer's open intake gather.
 *
 * The intake gather is entrypoint-driven: each data-type entrypoint is a
 * canonical entrypoint IRI, and the gather/source helpers open the matching
 * typed source stream directly.
 */

import type { CartographerState } from '../CartographerState.ts';
import type { SourcePayload } from '../entities/SourcePayload.ts';
import type { CanonicalEventVariant } from '../entities/index.ts';
import { EventStreamSource } from '../services/EventStreamSource.ts';
import { CARTOGRAPHER_IRIS } from '../cartographerIds.ts';

import type { GatherRecordType } from '@studnicky/dagonizer/contracts';
import type { NodeStateInterface } from '@studnicky/dagonizer/types';

type CartographerEventType = CanonicalEventVariant['eventType'];
type CartographerIntakeState = NodeStateInterface & Pick<CartographerState, 'eventConfig' | 'streamCount'>;

class SourcePayloadStream {
  private constructor() { /* static-only */ }

  static async *roundRobin(streams: readonly AsyncIterable<SourcePayload>[]): AsyncIterable<SourcePayload> {
    const active = streams.map((stream) => stream[Symbol.asyncIterator]());
    while (active.length > 0) {
      for (let i = 0; i < active.length;) {
        const step = await active[i]?.next();
        if (step === undefined || step.done === true) {
          active.splice(i, 1);
          continue;
        }
        yield step.value;
        i++;
      }
    }
  }

  static async *skip(stream: AsyncIterable<SourcePayload>, count: number): AsyncIterable<SourcePayload> {
    let skipped = 0;
    for await (const item of stream) {
      if (skipped < count) {
        skipped++;
        continue;
      }
      yield item;
    }
  }

  static async *empty(): AsyncIterable<SourcePayload> {
    return;
  }
}

export class CartographerSourceIntake {
  private constructor() { /* static-only */ }

  static isState(state: NodeStateInterface): state is CartographerIntakeState {
    const eventConfig = Reflect.get(state, 'eventConfig');
    return eventConfig !== null
      && typeof eventConfig === 'object'
      && typeof Reflect.get(state, 'streamCount') === 'number';
  }

  static streamFor(state: CartographerIntakeState, eventType: CartographerEventType): AsyncIterable<SourcePayload> {
    const totalCount = state.streamCount > 0 ? state.streamCount : undefined;
    return CartographerSourceIntake.filterType(
      EventStreamSource.streamTyped(state.eventConfig, totalCount),
      eventType,
    );
  }

  static mergedFor(state: CartographerState, resumeAfter: number = 0): AsyncIterable<SourcePayload> {
    const streams = CARTOGRAPHER_IRIS.intakeEventTypes.map((eventType) =>
      CartographerSourceIntake.streamFor(state, eventType),
    );
    const merged = SourcePayloadStream.roundRobin(streams);
    return resumeAfter > 0 ? SourcePayloadStream.skip(merged, resumeAfter) : merged;
  }

  static mergeRecords(
    records: readonly GatherRecordType[],
    state: NodeStateInterface,
  ): AsyncIterable<SourcePayload> {
    if (!CartographerSourceIntake.isState(state)) return SourcePayloadStream.empty();
    const streams: AsyncIterable<SourcePayload>[] = [];
    for (const source of CARTOGRAPHER_IRIS.intakeEventTypes) {
      const record = records.find((candidate) => CartographerSourceIntake.sourceType(candidate.source) === source);
      if (record === undefined) continue;
      streams.push(CartographerSourceIntake.streamFor(state, source));
    }
    return SourcePayloadStream.roundRobin(streams);
  }

  private static sourceType(source: string): CartographerEventType | null {
    const marker = '/entrypoint/';
    const index = source.indexOf(marker);
    if (index < 0) return null;
    const label = decodeURIComponent(source.slice(index + marker.length));
    return CARTOGRAPHER_IRIS.intakeEventTypes.includes(label as CartographerEventType)
      ? (label as CartographerEventType)
      : null;
  }

  private static async *filterType(
    stream: AsyncIterable<SourcePayload>,
    eventType: CartographerEventType,
  ): AsyncIterable<SourcePayload> {
    for await (const item of stream) {
      if (item.eventType === eventType) yield item;
    }
  }
}
ts
export class SourceIntakeGather extends GatherStrategy {
  readonly name = 'source-intake';
  readonly '@id' = 'urn:noocodec:node:source-intake';

  override initial(
    _config: GatherConfigType,
    state: NodeStateInterface,
    accessor: StateAccessorInterface,
  ): void {
    accessor.set(state, 'sources', []);
  }

  override reduce(
    _config: GatherConfigType,
    batch: Parameters<GatherStrategy['reduce']>[1],
    state: NodeStateInterface,
    accessor: StateAccessorInterface,
  ): void {
    const records: GatherRecordType[] = [];
    for (const item of batch) records.push(item.state);
    accessor.set(state, 'sources', CartographerSourceIntake.mergeRecords(records, state));
  }
}

GatherStrategies.register(new SourceIntakeGather());

canonicalizeCore — timestamp and location normalization

After geo-enrichment sets state.geoContext.timezone, canonicalizeCore converts the raw timestamp to a UTC epoch, then derives the local time at the scan's IANA timezone using Intl.DateTimeFormat. Cross-zone journeys show different local times and UTC offsets per scan.

ts
export class CanonicalizeCoreNode extends MonadicNode<CartographerState, 'normalized' | 'rejected'> {
  readonly '@id' = 'urn:noocodec:node:canonicalize-core';
  readonly 'name' = 'canonicalize-core';
  readonly 'outputs' = ['normalized', 'rejected'] as const;

  override get outputSchema(): Record<'normalized' | 'rejected', SchemaObjectType> {
    return {
      'normalized': { 'type': 'object' },
      'rejected':   { 'type': 'object' },
    };
  }

  override async execute(
    batch: Batch<CartographerState>,
    _context: NodeContextType,
  ): Promise<RoutedBatchType<'normalized' | 'rejected', CartographerState>> {
    const acc = new Map<'normalized' | 'rejected', ItemType<CartographerState>[]>();

    for (const item of batch) {
      const result = this.routeItem(item.state);
      for (const error of result.errors) {
        item.state.collectError(error);
      }
      const bucket = acc.get(result.output);
      if (bucket === undefined) {
        acc.set(result.output, [item]);
      } else {
        bucket.push(item);
      }
    }

    const routed = new Map<'normalized' | 'rejected', Batch<CartographerState>>();
    for (const [output, items] of acc) {
      routed.set(output, Batch.from(items));
    }
    return routed;
  }

  private routeItem(state: CartographerState): NodeOutputType<'normalized' | 'rejected'> {
    const raw = state.raw;

    const epochMs = TimeNormalizer.toEpochMs(raw.rawTimestamp);
    if (!isFinite(epochMs) || epochMs <= 0) {
      return NodeOutput.create('rejected');
    }

    const dispatchEpochMs = TimeNormalizer.toEpochMs(raw.rawDispatchAt);
    const validDispatch = isFinite(dispatchEpochMs) && dispatchEpochMs > 0 ? dispatchEpochMs : epochMs;

    const promisedEpochMs = TimeNormalizer.toEpochMs(raw.rawPromisedDeliveryAt);
    const validPromised = isFinite(promisedEpochMs) && promisedEpochMs > 0 ? promisedEpochMs : validDispatch + 7 * 86_400_000;

    const { localIso, utcOffset } = TimeZoneResolver.localParts(epochMs, state.geoContext.timezone);

    const { carrierId, carrierName } = CarrierRegistry.canonical(raw.carrier);
    const countryIso3 = CountryCodes.toIso3(raw.recipientCountry);
    const disruptionHours = Disruptions.hoursFor(raw.disruptionReason);

    // Derive classification at weightGrams=0. canonicalizeFacility will override
    // weightGrams/serviceTier/sizeTier with the real weight for facility-scan events.
    const status      = EventClassifier.eventType(raw.rawStatus);
    const serviceTier = EventClassifier.serviceTier(carrierId, 0);
    const sizeTier    = EventClassifier.sizeTier(0);

    state.normalized = {
      'shipmentId':       raw.shipmentId,
      'scanSeq':          raw.scanSeq,
      'epochMs':          epochMs,
      'dispatchEpochMs':  validDispatch,
      'isoTimestamp':     TimeNormalizer.toIso(epochMs),
      'localIso':         localIso,
      'utcOffset':        utcOffset,
      'carrierId':        carrierId,
      'carrierName':      carrierName,
      'countryIso3':      countryIso3,
      'weightGrams':      0,
      'status':           status,
      'serviceTier':      serviceTier,
      'sizeTier':         sizeTier,
      'lineItems':        [{ 'productId': '', 'quantity': 1 }],
      'facilityId':       '',
      'latitude':         raw.latitude,
      'longitude':        raw.longitude,
      'legFromLat':       raw.legFromLat,
      'legFromLng':       raw.legFromLng,
      'originLat':        raw.originLat,
      'originLng':        raw.originLng,
      'destLat':          raw.destLat,
      'destLng':          raw.destLng,
      'recipientName':    '',
      'recipientEmail':   '',
      'recipientPhone':   '',
      'recipientAddress': '',
      'recipientCountry': raw.recipientCountry,
      'marketingConsent': false,
      'promisedEpochMs':  validPromised,
      'disruptionHours':  disruptionHours,
      'disruptionReason': raw.disruptionReason,
    };

    return NodeOutput.create('normalized');
  }
}

export const canonicalizeCore = new CanonicalizeCoreNode();

aggregateEvent — writes the enriched record

Pulls every enrichment result out of the clone's state and assembles the compact EnrichedShipment record. The routing decisions, redacted PII sample, and pricing/ shipping/ETA figures all land here.

ts
export class AggregateEventNode extends MonadicNode<CartographerState, 'done'> {
  readonly '@id' = 'urn:noocodec:node:aggregate-event';
  readonly 'name' = 'aggregate-event';
  readonly 'outputs' = ['done'] as const;

  private static readonly DEFAULT_GEO_LABEL = 'Unmapped';

  override get outputSchema(): Record<'done', SchemaObjectType> {
    return {
      'done': { 'type': 'object' },
    };
  }

  override async execute(
    batch: Batch<CartographerState>,
    _context: NodeContextType,
  ): Promise<RoutedBatchType<'done', CartographerState>> {
    for (const item of batch) {
      const state = item.state;
      const norm = state.normalized;
      const geo  = state.geoContext;
      const gdpr = state.gdprResult;
      const po   = state.pricedOrder;
      const sq   = state.shippingQuote;
      const de   = state.deliveryEstimate;
      const ev   = state.currentEvent;

      const isException = norm.status === 'EXCEPTION';

      state.enriched = {
        'shipmentId':       norm.shipmentId,
        'scanSeq':          norm.scanSeq,
        'epochMs':          norm.epochMs,
        'localIso':         norm.localIso,
        'utcOffset':        norm.utcOffset,
        'timezone':         geo.timezone,
        'jurisdiction':     geo.jurisdiction,
        // Macro continent for the per-region insights rollup (from the real API).
        'continent':        geo.continent || AggregateEventNode.DEFAULT_GEO_LABEL,
        'region':           geo.region || AggregateEventNode.DEFAULT_GEO_LABEL,
        'country':          geo.country || AggregateEventNode.DEFAULT_GEO_LABEL,
        'hub':              geo.hub || AggregateEventNode.DEFAULT_GEO_LABEL,
        'geoStatus':        geo.status,
        // Stored coords come from currentEvent, which GDPR coarsened in-place
        // when the jurisdiction is strict or consent is not valid.
        'lat':              ev.latitude,
        'lng':              ev.longitude,
        'coordsCoarsened':  gdpr.coordsCoarsened,
        'legKm':            state.legKm,
        'status':           norm.status,
        'serviceTier':      norm.serviceTier,
        'sizeTier':         norm.sizeTier,
        'onTime':           de.onTime,
        'exception':        isException,
        'consentStatus':    gdpr.consentStatus,
        'disruptionReason': norm.disruptionReason,
        'subtotalUsdMinor': po.subtotalUsdMinor,
        'currency':         po.currency,
        'shippingUsdMinor': sq.costUsdMinor,
        'distanceKm':       sq.distanceKm,
        'transitHours':     de.transitHours,
        'delayHours':       de.delayHours,
        'redactionApplied': gdpr.redactionApplied,
        'redactedSample': {
          'recipientName':  ev.recipientName,
          'recipientEmail': ev.recipientEmail,
          'recipientPhone': ev.recipientPhone,
        },
        // This scan's conditional-routing decisions (RAN vs SKIPPED per branch),
        // recorded by the route-* nodes on this clone. The parent's summarize
        // totals them into the savings view.
        'routing': { ...state.routing },
      };
    }

    return RoutedBatch.create('done', batch);
  }
}

summarizeInsights — finalize insight views

In the streaming path (the browser demo and any caller using insights-fold) the insights-fold gather accumulates state.insights, state.journeys, and state.sampleRecords incrementally as each clone completes, so summarizeInsights is a pure pass-through — it detects the pre-populated maps and routes success immediately. The records-based fold (iterating state.records) is retained as a default path for callers that use the array path without the insights-fold gather. Either way the final state exposes:

  • Per-continent rollup (state.insights): counts, on-time rate, revenue (USD), distance.
  • Per-journey rollup (state.journeys): grouped by shipmentId, ordered by epoch; path distance, elapsed time, timezones crossed, jurisdictions traversed.
ts
export class SummarizeInsightsNode extends MonadicNode<CartographerState, 'success'> {
  readonly '@id' = 'urn:noocodec:node:summarize';
  private static readonly sizeTierDispatch: Readonly<Record<SizeTierKey, (entry: RegionInsights) => void>> = {
    'envelope': (entry) => { entry.sizeTierEnvelope++; },
    'small':    (entry) => { entry.sizeTierSmall++; },
    'medium':   (entry) => { entry.sizeTierMedium++; },
    'large':    (entry) => { entry.sizeTierLarge++; },
    'freight':  (entry) => { entry.sizeTierFreight++; },
  };
  readonly 'name' = 'summarize';
  readonly 'outputs' = ['success'] as const;

  override get outputSchema(): Record<'success', SchemaObjectType> {
    return {
      'success': { 'type': 'object' },
    };
  }

  override async execute(
    batch: Batch<CartographerState>,
    _context: NodeContextType,
  ): Promise<RoutedBatchType<'success', CartographerState>> {
    for (const item of batch) {
      this.summarizeItem(item.state);
    }
    return RoutedBatch.create('success', batch);
  }

  private summarizeItem(state: CartographerState): void {
    // Streaming path: insights-fold gather already produced state.insights,
    // state.journeys, and state.sampleRecords with bounded memory. Nothing to do.
    if (state.insights.size > 0 || state.journeys.size > 0) {
      return;
    }

    // Array-path default: fold state.records into insights and journeys for
    // callers that did not use the insights-fold gather strategy.
    state.insights = new Map<string, RegionInsights>();
    state.journeys = new Map<string, JourneyInsights>();

    // ── (b) Group scans by shipmentId for per-journey reconstruction ──────────
    const scansByShipment = new Map<string, JourneyScan[]>();

    for (const record of state.records) {
      if (!record.shipmentId) continue;

      // ── (a) per-region accumulation (rolled up to CONTINENT) ────────────────
      // Bucket by the macro continent the real geo API resolved (not the fine
      // subdivision/country), so the table reads ~6–8 rows. Maritime pings (open
      // water → no continent) collapse into one 'International Waters / Maritime'
      // bucket. The continent is always present (default 'Unmapped' upstream),
      // so the key is consistent — never a bare country code or subdivision.
      const key = record.geoStatus === 'water'
        ? 'International Waters / Maritime'
        : record.continent;
      let entry = state.insights.get(key);
      if (entry === undefined) {
        entry = {
          'region':               key,
          'country':              key,
          'hub':                  key,
          'deliveries':           0,
          'exceptions':           0,
          'onTimeCount':          0,
          'lateCount':            0,
          'totalSubtotalUsdMinor': 0,
          'totalShippingUsdMinor': 0,
          'totalDistanceKm':      0,
          'totalDelayHours':      0,
          'consentValid':         0,
          'consentMissing':       0,
          'consentExpired':       0,
          'sizeTierEnvelope':     0,
          'sizeTierSmall':        0,
          'sizeTierMedium':       0,
          'sizeTierLarge':        0,
          'sizeTierFreight':      0,
          'shipmentCount':        0,
        };
        state.insights.set(key, entry);
      }

      entry.shipmentCount++;
      entry.totalSubtotalUsdMinor += record.subtotalUsdMinor;
      entry.totalShippingUsdMinor += record.shippingUsdMinor;
      entry.totalDistanceKm       += record.distanceKm;

      // On-time is only meaningful for order-lane events that ran the ETA node;
      // position/sensor/customs events skip pricing/eta (the branching saves it),
      // so they are NOT counted toward on-time% (which would otherwise read 0%).
      if (record.routing.etaRun) {
        if (record.onTime) entry.onTimeCount++;
        else {
          entry.lateCount++;
          entry.totalDelayHours += record.delayHours;
        }
      }
      if (record.status === 'DELIVERED') entry.deliveries++;
      if (record.exception) entry.exceptions++;
      if (record.consentStatus === 'valid')   entry.consentValid++;
      if (record.consentStatus === 'missing') entry.consentMissing++;
      if (record.consentStatus === 'expired') entry.consentExpired++;

      SummarizeInsightsNode.sizeTierDispatch[record.sizeTier]?.(entry);

      // ── (b) collect the scan for this journey ───────────────────────────────
      let scans = scansByShipment.get(record.shipmentId);
      if (scans === undefined) {
        scans = [];
        scansByShipment.set(record.shipmentId, scans);
      }
      scans.push({
        'scanSeq':          record.scanSeq,
        'epochMs':          record.epochMs,
        'localIso':         record.localIso,
        'utcOffset':        record.utcOffset,
        'timezone':         record.timezone,
        'jurisdiction':     record.jurisdiction,
        'status':           record.status,
        'hub':              record.hub,
        'region':           record.region,
        'country':          record.country,
        'lat':              record.lat,
        'lng':              record.lng,
        'legKm':            record.legKm,
        'disruptionReason': record.disruptionReason,
      });
    }

    // ── (b) build the per-journey aggregates ──────────────────────────────────
    for (const [shipmentId, rawScans] of scansByShipment) {
      // Order by scanSeq (the authoritative journey order); epochMs is a display
      // value that can collapse/reorder under lossy raw timestamp formats, so it
      // is only a tiebreak.
      const scans = [...rawScans].sort((a, b) => a.scanSeq - b.scanSeq || a.epochMs - b.epochMs);
      const first = scans[0];
      const last  = scans[scans.length - 1];
      if (first === undefined || last === undefined) continue;

      let pathKm = 0;
      let minEpoch = first.epochMs;
      let maxEpoch = first.epochMs;
      const offsets: string[] = [];
      const timezones: string[] = [];
      const jurisdictions: string[] = [];
      const statusProgression: string[] = [];
      let delivered = false;

      for (const s of scans) {
        pathKm += s.legKm;
        if (s.epochMs < minEpoch) minEpoch = s.epochMs;
        if (s.epochMs > maxEpoch) maxEpoch = s.epochMs;
        if (!offsets.includes(s.utcOffset)) offsets.push(s.utcOffset);
        if (!timezones.includes(s.timezone)) timezones.push(s.timezone);
        if (!jurisdictions.includes(s.jurisdiction)) jurisdictions.push(s.jurisdiction);
        statusProgression.push(s.status);
        if (s.status === 'DELIVERED') delivered = true;
      }

      // Shipment-level facts (on-time, delay, pricing) come from an ORDER-lane
      // record of the journey — one that actually ran pricing/eta. Position/
      // sensor/customs scans skip that work, so prefer an eta-bearing record;
      // use any record only if the journey has no order-lane scan.
      const orderRecord = state.records.find(
        (r) => r.shipmentId === shipmentId && r.shipmentId.length > 0 && r.routing.etaRun,
      );
      const deliveryRecord = orderRecord
        ?? state.records.find((r) => r.shipmentId === shipmentId && r.shipmentId.length > 0);
      const onTime = deliveryRecord?.onTime ?? false;
      const delayHours = deliveryRecord?.delayHours ?? 0;
      const subtotalUsdMinor = deliveryRecord?.subtotalUsdMinor ?? 0;
      const shippingUsdMinor = deliveryRecord?.shippingUsdMinor ?? 0;

      const journey: JourneyInsights = {
        'shipmentId':        shipmentId,
        'scans':             scans,
        'scanCount':         scans.length,
        'pathKm':            pathKm,
        'firstEpochMs':      minEpoch,
        'lastEpochMs':       maxEpoch,
        'elapsedHours':      (maxEpoch - minEpoch) / 3_600_000,
        'timezones':         timezones,
        'offsets':           offsets,
        'jurisdictions':     jurisdictions,
        'statusProgression': statusProgression,
        'lastStatus':        last.status,
        'lastHub':           last.hub,
        'delivered':         delivered,
        'onTime':            onTime,
        'delayHours':        delayHours,
        'subtotalUsdMinor':  subtotalUsdMinor,
        'shippingUsdMinor':  shippingUsdMinor,
      };
      state.journeys.set(shipmentId, journey);
    }
  }
}

export const summarizeInsights = new SummarizeInsightsNode();

Entities

EnrichedShipment — the per-scan enriched record

ts
import type { FromSchema } from 'json-schema-to-ts';
import { Validator } from '@studnicky/dagonizer/validation';

export const EnrichedShipmentSchema = {
  '$id': 'https://noocodec.dev/schemas/cartographer/EnrichedShipment',
  '$schema': 'https://json-schema.org/draft/2020-12/schema',
  'type': 'object',
  'required': [
    'shipmentId', 'scanSeq', 'epochMs', 'localIso', 'utcOffset', 'timezone', 'jurisdiction',
    'continent', 'region', 'country', 'hub', 'geoStatus',
    'lat', 'lng', 'coordsCoarsened', 'legKm',
    'status', 'serviceTier', 'sizeTier',
    'onTime', 'exception', 'consentStatus', 'disruptionReason',
    'subtotalUsdMinor', 'currency',
    'shippingUsdMinor', 'distanceKm',
    'transitHours', 'delayHours',
    'redactionApplied', 'redactedSample', 'routing',
  ],
  'properties': {
    'shipmentId':        { 'type': 'string', 'minLength': 1 },
    'scanSeq':           { 'type': 'number', 'minimum': 0 },
    'epochMs':           { 'type': 'number' },
    'localIso':          { 'type': 'string' },
    'utcOffset':         { 'type': 'string' },
    'timezone':          { 'type': 'string' },
    'jurisdiction':      { 'type': 'string', 'enum': ['GDPR', 'UK-GDPR', 'CCPA', 'LGPD', 'APPI', 'baseline', 'international-waters'] },
    // Macro continent (from a real API) — the per-region insights table buckets by this.
    'continent':         { 'type': 'string', 'minLength': 1 },
    'region':            { 'type': 'string', 'minLength': 1 },
    'country':           { 'type': 'string', 'minLength': 1 },
    'hub':               { 'type': 'string', 'minLength': 1 },
    'geoStatus':         { 'type': 'string', 'enum': ['land', 'water', 'coastal', 'unmapped'] },
    'lat':               { 'type': 'number' },
    'lng':               { 'type': 'number' },
    'coordsCoarsened':   { 'type': 'boolean' },
    'legKm':             { 'type': 'number', 'minimum': 0 },
    'status':            { 'type': 'string', 'enum': ['SCAN', 'DEPARTURE', 'ARRIVAL', 'OUT_FOR_DELIVERY', 'DELIVERED', 'EXCEPTION'] },
    'serviceTier':       { 'type': 'string', 'enum': ['express', 'standard', 'economy'] },
    'sizeTier':          { 'type': 'string', 'enum': ['envelope', 'small', 'medium', 'large', 'freight'] },
    'onTime':            { 'type': 'boolean' },
    'exception':         { 'type': 'boolean' },
    'consentStatus':     { 'type': 'string', 'enum': ['valid', 'missing', 'expired'] },
    'disruptionReason':  { 'type': 'string' },
    'subtotalUsdMinor':  { 'type': 'number', 'minimum': 0 },
    'currency':          { 'type': 'string', 'minLength': 3, 'maxLength': 3 },
    'shippingUsdMinor':  { 'type': 'number', 'minimum': 0 },
    'distanceKm':        { 'type': 'number', 'minimum': 0 },
    'transitHours':      { 'type': 'number', 'minimum': 0 },
    'delayHours':        { 'type': 'number', 'minimum': 0 },
    'redactionApplied':  { 'type': 'boolean' },
    'redactedSample': {
      'type': 'object',
      'required': ['recipientName', 'recipientEmail', 'recipientPhone'],
      'properties': {
        'recipientName':  { 'type': 'string' },
        'recipientEmail': { 'type': 'string' },
        'recipientPhone': { 'type': 'string' },
      },
      'additionalProperties': false,
    },
    // This scan's conditional-routing decisions (RAN vs SKIPPED per branch),
    // including REAL geo-API call accounting (reverse-geocode + ip-geolocate).
    'routing': {
      'type': 'object',
      'required': [
        'path',
        'geoLookupRun', 'geoLookupSkipped',
        'ipGeolocateRun', 'ipGeolocateSkipped',
        'geoConfidence', 'geoModalities',
        'geoSourceModel', 'geoSecondaryLookupUsed',
        'redactionRun', 'redactionSkipped',
        'pricingRun', 'pricingSkipped',
        'etaRun', 'etaSkipped',
        'coldChainRun', 'customsDwellRun',
      ],
      'properties': {
        // The per-event-type enrichment lane this event took.
        'path':              { 'type': 'string', 'enum': ['geo-only', 'sensor', 'order', 'customs'] },
        // Whether the whole geo-resolve sub-DAG (real API calls) ran or was skipped.
        'geoLookupRun':      { 'type': 'boolean' },
        'geoLookupSkipped':  { 'type': 'boolean' },
        // Real API-call accounting inside geo-resolve.
        'ipGeolocateRun':    { 'type': 'boolean' },
        'ipGeolocateSkipped': { 'type': 'boolean' },
        // Multi-modal fusion outcome carried for the report.
        'geoConfidence':     { 'type': 'number', 'minimum': 0, 'maximum': 1 },
        'geoModalities':     { 'type': 'array', 'items': { 'type': 'string' } },
        // Source-model classification: which geo signal classify-geo-source selected.
        'geoSourceModel':    { 'type': 'string' },
        // Whether CoordTimezone secondary lookup fired.
        'geoSecondaryLookupUsed': { 'type': 'boolean' },
        'redactionRun':      { 'type': 'boolean' },
        'redactionSkipped':  { 'type': 'boolean' },
        'pricingRun':        { 'type': 'boolean' },
        'pricingSkipped':    { 'type': 'boolean' },
        'etaRun':            { 'type': 'boolean' },
        'etaSkipped':        { 'type': 'boolean' },
        'coldChainRun':      { 'type': 'boolean' },
        'customsDwellRun':   { 'type': 'boolean' },
      },
      'additionalProperties': false,
    },
  },
  'additionalProperties': false,
} as const;

export type EnrichedShipment = FromSchema<typeof EnrichedShipmentSchema>;

const enrichedShipmentValidator = Validator.compile<EnrichedShipment>(EnrichedShipmentSchema);

export class EnrichedShipmentGuard {
  /**
   * Type-guard for EnrichedShipment. Narrows `unknown` to the schema-derived type
   * by verifying required fields that consumers rely on after narrowing.
   */
  static is(value: unknown): value is EnrichedShipment {
    return enrichedShipmentValidator.is(value);
  }
}

CanonicalEventVariant — the per-type event model

The canonical model is a discriminated union on eventType. Each member carries only the fields its event type owns. Five types are generated:

  • position-ping — a moving asset's satellite position fix with GPS coordinates
  • facility-scan — a parcel scanned at a depot or facility; carries PII and order fields
  • sensor-reading — cold-chain telemetry (temperature, humidity, shock); triggers the cold-chain check
  • customs-event — a customs clearance or hold event; carries customsStatus
  • delivery-confirmation — proof-of-delivery (the terminal event); carries PII and delivered: true

Format is an independent axis: each event type specifies a format mix (csv/json/ndjson/yaml with per-format weights and compression), so position-pings might arrive as gzip JSON while facility-scans come as CSV. The same event type can appear in multiple formats in one feed.

ts
import type { SourcePayload } from './SourcePayload.ts';
import {
  CustomsEventSchema,
  type CustomsEvent,
} from './events/CustomsEvent.ts';
import {
  DeliveryConfirmationEventSchema,
  type DeliveryConfirmationEvent,
} from './events/DeliveryConfirmationEvent.ts';
import {
  FacilityScanEventSchema,
  type FacilityScanEvent,
} from './events/FacilityScanEvent.ts';
import {
  PositionPingEventSchema,
  type PositionPingEvent,
} from './events/PositionPingEvent.ts';
import {
  SensorReadingEventSchema,
  type SensorReadingEvent,
} from './events/SensorReadingEvent.ts';
import { Validator } from '@studnicky/dagonizer/validation';

export const CanonicalEventVariantSchema = {
  '$id': 'https://noocodec.dev/schemas/cartographer/CanonicalEventVariant',
  '$schema': 'https://json-schema.org/draft/2020-12/schema',
  'oneOf': [
    PositionPingEventSchema,
    FacilityScanEventSchema,
    SensorReadingEventSchema,
    CustomsEventSchema,
    DeliveryConfirmationEventSchema,
  ],
} as const;

export type CanonicalEventVariant =
  | PositionPingEvent
  | FacilityScanEvent
  | SensorReadingEvent
  | CustomsEvent
  | DeliveryConfirmationEvent;

const canonicalEventVariantValidator = Validator.compile<CanonicalEventVariant>(CanonicalEventVariantSchema);

// Complete 'position-ping' default. The producer overrides only what it knows;
// every required envelope/body field is present so the consumer never sees a hole.
const POSITION_PING_DEFAULT: PositionPingEvent = {
  'shipmentId': 'unknown',
  'eventId': 'unknown',
  'epochMs': 0,
  'eventType': 'position-ping',
  'sourceId': 'unknown',
  'sourceFormat': 'json',
  'sourceCompression': 'none',
  'body': {
    'scanSeq': 0,
    'latitude': 0,
    'longitude': 0,
    'ipAddress': '',
    'localeTag': '',
    'countryCode': '',
    'legFromLat': 0,
    'legFromLng': 0,
    'originLat': 0,
    'originLng': 0,
    'destLat': 0,
    'destLng': 0,
    'carrier': '',
    'status': '',
    'rawTimestamp': '',
    'address': '',
    'phone': '',
  },
};

// Per-type body defaults for fromSourcePayload. Each constant covers ONLY the
// fields owned by that type. Declaration order matches the schema's `required`
// array for V8 shape stability.

const POSITION_PING_BODY_DEFAULT: PositionPingEvent['body'] = {
  'scanSeq':      0,
  'latitude':     0,
  'longitude':    0,
  'ipAddress':    '',
  'localeTag':    '',
  'countryCode':  '',
  'legFromLat':   0,
  'legFromLng':   0,
  'originLat':    0,
  'originLng':    0,
  'destLat':      0,
  'destLng':      0,
  'carrier':      '',
  'status':       '',
  'rawTimestamp': '',
  'address':      '',
  'phone':        '',
};

const FACILITY_SCAN_BODY_DEFAULT: FacilityScanEvent['body'] = {
  'scanSeq':              0,
  'latitude':             0,
  'longitude':            0,
  'ipAddress':            '',
  'localeTag':            '',
  'countryCode':          '',
  'legFromLat':           0,
  'legFromLng':           0,
  'originLat':            0,
  'originLng':            0,
  'destLat':              0,
  'destLng':              0,
  'carrier':              '',
  'status':               '',
  'rawTimestamp':         '',
  'facilityId':           '',
  'weight':               0,
  'weightUnit':           'kg',
  'lineItems':            [],
  'rawDispatchAt':        '',
  'rawPromisedDeliveryAt': '',
  'disruptionReason':     '',
  'recipientName':        '',
  'recipientEmail':       '',
  'recipientPhone':       '',
  'recipientAddress':     '',
  'recipientCountry':     '',
  'marketingConsent':     false,
  'lawfulBasis':          'contract',
  'specialCategory':      'none',
  'address':              '',
  'phone':                '',
};

const SENSOR_READING_BODY_DEFAULT: SensorReadingEvent['body'] = {
  'scanSeq':      0,
  'latitude':     0,
  'longitude':    0,
  'ipAddress':    '',
  'localeTag':    '',
  'countryCode':  '',
  'legFromLat':   0,
  'legFromLng':   0,
  'originLat':    0,
  'originLng':    0,
  'destLat':      0,
  'destLng':      0,
  'carrier':      '',
  'status':       '',
  'rawTimestamp': '',
  'tempC':        0,
  'humidityPct':  0,
  'shockG':       0,
  'address':      '',
  'phone':        '',
};

const CUSTOMS_EVENT_BODY_DEFAULT: CustomsEvent['body'] = {
  'scanSeq':       0,
  'latitude':      0,
  'longitude':     0,
  'ipAddress':     '',
  'localeTag':     '',
  'countryCode':   '',
  'legFromLat':    0,
  'legFromLng':    0,
  'originLat':     0,
  'originLng':     0,
  'destLat':       0,
  'destLng':       0,
  'carrier':       '',
  'status':        '',
  'rawTimestamp':  '',
  'customsStatus': '',
  'address':      '',
  'phone':        '',
};

const DELIVERY_BODY_DEFAULT: DeliveryConfirmationEvent['body'] = {
  'scanSeq':               0,
  'latitude':              0,
  'longitude':             0,
  'ipAddress':             '',
  'localeTag':             '',
  'countryCode':           '',
  'legFromLat':            0,
  'legFromLng':            0,
  'originLat':             0,
  'originLng':             0,
  'destLat':               0,
  'destLng':               0,
  'carrier':               '',
  'status':                '',
  'rawTimestamp':          '',
  'delivered':             false,
  'rawPromisedDeliveryAt': '',
  'disruptionReason':      '',
  'recipientName':         '',
  'recipientEmail':        '',
  'recipientPhone':        '',
  'recipientAddress':      '',
  'recipientCountry':      '',
  'marketingConsent':      false,
  'lawfulBasis':           'contract',
  'specialCategory':       'none',
  'address':               '',
  'phone':                 '',
};

interface FromSourcePayloadContext {
  readonly envelope: {
    readonly shipmentId: string;
    readonly eventId: string;
    readonly epochMs: number;
    readonly sourceId: string;
    readonly sourceFormat: PositionPingEvent['sourceFormat'];
    readonly sourceCompression: PositionPingEvent['sourceCompression'];
  };
  readonly decoded: Record<string, unknown>;
  readonly sharedGeo: {
    readonly scanSeq: number;
    readonly latitude: number;
    readonly longitude: number;
    readonly ipAddress: string;
    readonly localeTag: string;
    readonly countryCode: string;
    readonly legFromLat: number;
    readonly legFromLng: number;
    readonly originLat: number;
    readonly originLng: number;
    readonly destLat: number;
    readonly destLng: number;
    readonly carrier: string;
    readonly status: string;
    readonly rawTimestamp: string;
    readonly address: string;
    readonly phone: string;
  };
  readonly preResolvedGeo: { readonly country: string; readonly continent: string; readonly region: string } | undefined;
}

export class CanonicalEventVariantBuilder {
  private static readonly fromSourcePayloadDispatch: Readonly<Record<string, (ctx: FromSourcePayloadContext) => CanonicalEventVariant>> = {
    'position-ping': ({ envelope, sharedGeo, preResolvedGeo }) => {
      const body: PositionPingEvent['body'] = {
        'scanSeq':      sharedGeo.scanSeq,
        'latitude':     sharedGeo.latitude,
        'longitude':    sharedGeo.longitude,
        'ipAddress':    sharedGeo.ipAddress,
        'localeTag':    sharedGeo.localeTag,
        'countryCode':  sharedGeo.countryCode,
        'legFromLat':   sharedGeo.legFromLat,
        'legFromLng':   sharedGeo.legFromLng,
        'originLat':    sharedGeo.originLat,
        'originLng':    sharedGeo.originLng,
        'destLat':      sharedGeo.destLat,
        'destLng':      sharedGeo.destLng,
        'carrier':      sharedGeo.carrier,
        'status':       sharedGeo.status,
        'rawTimestamp': sharedGeo.rawTimestamp.length > 0 ? sharedGeo.rawTimestamp : POSITION_PING_BODY_DEFAULT.rawTimestamp,
        'address':      sharedGeo.address,
        'phone':        sharedGeo.phone,
      };
      return { ...envelope, 'eventType': 'position-ping', 'body': body, ...(preResolvedGeo !== undefined && { 'geo': preResolvedGeo }) };
    },
    'facility-scan': ({ envelope, decoded, sharedGeo, preResolvedGeo }) => {
      const body: FacilityScanEvent['body'] = {
        'scanSeq':               sharedGeo.scanSeq,
        'latitude':              sharedGeo.latitude,
        'longitude':             sharedGeo.longitude,
        'ipAddress':             sharedGeo.ipAddress,
        'localeTag':             sharedGeo.localeTag,
        'countryCode':           sharedGeo.countryCode,
        'legFromLat':            sharedGeo.legFromLat,
        'legFromLng':            sharedGeo.legFromLng,
        'originLat':             sharedGeo.originLat,
        'originLng':             sharedGeo.originLng,
        'destLat':               sharedGeo.destLat,
        'destLng':               sharedGeo.destLng,
        'carrier':               sharedGeo.carrier,
        'status':                sharedGeo.status,
        'rawTimestamp':          sharedGeo.rawTimestamp.length > 0 ? sharedGeo.rawTimestamp : FACILITY_SCAN_BODY_DEFAULT.rawTimestamp,
        'facilityId':            CanonicalEventVariantBuilder.str(decoded['facilityId']),
        'weight':                CanonicalEventVariantBuilder.num(decoded['weight']),
        'weightUnit':            CanonicalEventVariantBuilder.weightUnit(decoded['weightUnit']),
        'lineItems':             CanonicalEventVariantBuilder.lineItems(decoded['lineItems']),
        'rawDispatchAt':         CanonicalEventVariantBuilder.str(decoded['dispatchRaw']),
        'rawPromisedDeliveryAt': CanonicalEventVariantBuilder.str(decoded['promisedRaw']),
        'disruptionReason':      CanonicalEventVariantBuilder.str(decoded['disruptionReason']),
        'recipientName':         CanonicalEventVariantBuilder.str(decoded['recipientName']),
        'recipientEmail':        CanonicalEventVariantBuilder.str(decoded['recipientEmail']),
        'recipientPhone':        CanonicalEventVariantBuilder.str(decoded['recipientPhone']),
        'recipientAddress':      CanonicalEventVariantBuilder.str(decoded['recipientAddress']),
        'recipientCountry':      CanonicalEventVariantBuilder.str(decoded['recipientCountry']),
        'marketingConsent':      CanonicalEventVariantBuilder.bool(decoded['marketingConsent']),
        'lawfulBasis':           CanonicalEventVariantBuilder.lawfulBasis(decoded['lawfulBasis']),
        'specialCategory':       CanonicalEventVariantBuilder.specialCategory(decoded['specialCategory']),
        'address':               sharedGeo.address,
        'phone':                 sharedGeo.phone,
      };
      return { ...envelope, 'eventType': 'facility-scan', 'body': body, ...(preResolvedGeo !== undefined && { 'geo': preResolvedGeo }) };
    },
    'sensor-reading': ({ envelope, decoded, sharedGeo, preResolvedGeo }) => {
      const body: SensorReadingEvent['body'] = {
        'scanSeq':      sharedGeo.scanSeq,
        'latitude':     sharedGeo.latitude,
        'longitude':    sharedGeo.longitude,
        'ipAddress':    sharedGeo.ipAddress,
        'localeTag':    sharedGeo.localeTag,
        'countryCode':  sharedGeo.countryCode,
        'legFromLat':   sharedGeo.legFromLat,
        'legFromLng':   sharedGeo.legFromLng,
        'originLat':    sharedGeo.originLat,
        'originLng':    sharedGeo.originLng,
        'destLat':      sharedGeo.destLat,
        'destLng':      sharedGeo.destLng,
        'carrier':      sharedGeo.carrier,
        'status':       sharedGeo.status,
        'rawTimestamp': sharedGeo.rawTimestamp.length > 0 ? sharedGeo.rawTimestamp : SENSOR_READING_BODY_DEFAULT.rawTimestamp,
        'tempC':        CanonicalEventVariantBuilder.num(decoded['tempC']),
        'humidityPct':  CanonicalEventVariantBuilder.num(decoded['humidityPct']),
        'shockG':       CanonicalEventVariantBuilder.num(decoded['shockG']),
        'address':      sharedGeo.address,
        'phone':        sharedGeo.phone,
      };
      return { ...envelope, 'eventType': 'sensor-reading', 'body': body, ...(preResolvedGeo !== undefined && { 'geo': preResolvedGeo }) };
    },
    'customs-event': ({ envelope, decoded, sharedGeo, preResolvedGeo }) => {
      const body: CustomsEvent['body'] = {
        'scanSeq':       sharedGeo.scanSeq,
        'latitude':      sharedGeo.latitude,
        'longitude':     sharedGeo.longitude,
        'ipAddress':     sharedGeo.ipAddress,
        'localeTag':     sharedGeo.localeTag,
        'countryCode':   sharedGeo.countryCode,
        'legFromLat':    sharedGeo.legFromLat,
        'legFromLng':    sharedGeo.legFromLng,
        'originLat':     sharedGeo.originLat,
        'originLng':     sharedGeo.originLng,
        'destLat':       sharedGeo.destLat,
        'destLng':       sharedGeo.destLng,
        'carrier':       sharedGeo.carrier,
        'status':        sharedGeo.status,
        'rawTimestamp':  sharedGeo.rawTimestamp.length > 0 ? sharedGeo.rawTimestamp : CUSTOMS_EVENT_BODY_DEFAULT.rawTimestamp,
        'customsStatus': CanonicalEventVariantBuilder.str(decoded['customsStatus']),
        'address':       sharedGeo.address,
        'phone':         sharedGeo.phone,
      };
      return { ...envelope, 'eventType': 'customs-event', 'body': body, ...(preResolvedGeo !== undefined && { 'geo': preResolvedGeo }) };
    },
    'delivery-confirmation': ({ envelope, decoded, sharedGeo, preResolvedGeo }) => {
      const body: DeliveryConfirmationEvent['body'] = {
        'scanSeq':               sharedGeo.scanSeq,
        'latitude':              sharedGeo.latitude,
        'longitude':             sharedGeo.longitude,
        'ipAddress':             sharedGeo.ipAddress,
        'localeTag':             sharedGeo.localeTag,
        'countryCode':           sharedGeo.countryCode,
        'legFromLat':            sharedGeo.legFromLat,
        'legFromLng':            sharedGeo.legFromLng,
        'originLat':             sharedGeo.originLat,
        'originLng':             sharedGeo.originLng,
        'destLat':               sharedGeo.destLat,
        'destLng':               sharedGeo.destLng,
        'carrier':               sharedGeo.carrier,
        'status':                sharedGeo.status,
        'rawTimestamp':          sharedGeo.rawTimestamp.length > 0 ? sharedGeo.rawTimestamp : DELIVERY_BODY_DEFAULT.rawTimestamp,
        'delivered':             CanonicalEventVariantBuilder.bool(decoded['delivered']),
        'rawPromisedDeliveryAt': CanonicalEventVariantBuilder.str(decoded['promisedRaw']),
        'disruptionReason':      CanonicalEventVariantBuilder.str(decoded['disruptionReason']),
        'recipientName':         CanonicalEventVariantBuilder.str(decoded['recipientName']),
        'recipientEmail':        CanonicalEventVariantBuilder.str(decoded['recipientEmail']),
        'recipientPhone':        CanonicalEventVariantBuilder.str(decoded['recipientPhone']),
        'recipientAddress':      CanonicalEventVariantBuilder.str(decoded['recipientAddress']),
        'recipientCountry':      CanonicalEventVariantBuilder.str(decoded['recipientCountry']),
        'marketingConsent':      CanonicalEventVariantBuilder.bool(decoded['marketingConsent']),
        'lawfulBasis':           CanonicalEventVariantBuilder.lawfulBasis(decoded['lawfulBasis']),
        'specialCategory':       CanonicalEventVariantBuilder.specialCategory(decoded['specialCategory']),
        'address':               sharedGeo.address,
        'phone':                 sharedGeo.phone,
      };
      return { ...envelope, 'eventType': 'delivery-confirmation', 'body': body, ...(preResolvedGeo !== undefined && { 'geo': preResolvedGeo }) };
    },
  };
  /**
   * Type-guard for CanonicalEventVariant. Narrows `unknown` to the discriminated
   * union by verifying the object shape and eventType discriminant.
  */
  static is(value: unknown): value is CanonicalEventVariant {
    return canonicalEventVariantValidator.is(value);
  }

  static from(partial: Partial<PositionPingEvent> = {}): CanonicalEventVariant {
    return {
      ...POSITION_PING_DEFAULT,
      ...partial,
      'eventType': 'position-ping',
      'body': { ...POSITION_PING_DEFAULT.body, ...partial.body },
    };
  }

  // Private coercion helpers — mirror coerce-types node semantics without
  // importing the node. Defined locally so defaults live in one place.

  private static str(v: unknown): string {
    return typeof v === 'string' ? v : '';
  }

  private static num(v: unknown): number {
    if (typeof v === 'number' && isFinite(v)) return v;
    if (typeof v === 'string') { const n = Number(v); return isFinite(n) ? n : 0; }
    return 0;
  }

  private static bool(v: unknown): boolean {
    if (typeof v === 'boolean') return v;
    if (typeof v === 'string') return v === 'true' || v === '1';
    return false;
  }

  private static lawfulBasis(v: unknown): DeliveryConfirmationEvent['body']['lawfulBasis'] {
    return v === 'contract' || v === 'consent' || v === 'legitimate-interest' || v === 'none'
      ? v : 'contract';
  }

  private static specialCategory(v: unknown): DeliveryConfirmationEvent['body']['specialCategory'] {
    return v === 'health' ? 'health' : 'none';
  }

  private static weightUnit(v: unknown): FacilityScanEvent['body']['weightUnit'] {
    return v === 'lb' || v === 'kg' || v === 'g' || v === 'oz' ? v : 'kg';
  }

  private static lineItems(v: unknown): Array<{ 'productId': string; 'quantity': number }> {
    if (!Array.isArray(v)) return [];
    const out: Array<{ 'productId': string; 'quantity': number }> = [];
    for (const li of v) {
      if (li !== null && typeof li === 'object' && !Array.isArray(li)) {
        const o: Record<string, unknown> = { ...li };
        out.push({
          'productId': CanonicalEventVariantBuilder.str(o['productId']),
          'quantity':  CanonicalEventVariantBuilder.num(o['quantity']) || 1,
        });
      }
    }
    return out;
  }

  /**
   * Build a CanonicalEventVariant from a SourcePayload and its decoded canonical
   * record. Switches on payload.eventType (the authoritative type) and constructs
   * ONLY the variant member for that type, populating each owned body field from
   * the decoded record with a default for any genuinely absent field.
   *
   * Envelope fields (shipmentId, eventId, epochMs) come from the decoded record.
   * Provenance (sourceId, sourceFormat, sourceCompression) comes from the payload.
   * The rawTimestamp body field is decoded.epochRaw (the raw timestamp string).
   */
  static fromSourcePayload(
    payload: SourcePayload,
    decoded: Record<string, unknown>,
  ): CanonicalEventVariant {
    const shipmentId = CanonicalEventVariantBuilder.str(decoded['shipmentId']);
    const eventId    = CanonicalEventVariantBuilder.str(decoded['eventId']);
    const epochMs    = CanonicalEventVariantBuilder.num(decoded['epochMs']);

    const envelope = {
      'shipmentId':        shipmentId.length > 0 ? shipmentId : 'unknown',
      'eventId':           eventId.length > 0 ? eventId : 'unknown',
      'epochMs':           epochMs,
      'sourceId':          payload.sourceId,
      'sourceFormat':      payload.format,
      'sourceCompression': payload.compression,
    } as const;

    // Shared geometry fields present on every variant.
    const scanSeq    = CanonicalEventVariantBuilder.num(decoded['scanSeq']);
    const latitude   = CanonicalEventVariantBuilder.num(decoded['latitude']);
    const longitude  = CanonicalEventVariantBuilder.num(decoded['longitude']);
    const ipAddress   = CanonicalEventVariantBuilder.str(decoded['ipAddress']);
    const localeTag   = CanonicalEventVariantBuilder.str(decoded['localeTag']);
    const countryCode = CanonicalEventVariantBuilder.str(decoded['countryCode']);
    const legFromLat  = CanonicalEventVariantBuilder.num(decoded['legFromLat']);
    const legFromLng = CanonicalEventVariantBuilder.num(decoded['legFromLng']);
    const originLat  = CanonicalEventVariantBuilder.num(decoded['originLat']);
    const originLng  = CanonicalEventVariantBuilder.num(decoded['originLng']);
    const destLat    = CanonicalEventVariantBuilder.num(decoded['destLat']);
    const destLng    = CanonicalEventVariantBuilder.num(decoded['destLng']);
    const carrier    = CanonicalEventVariantBuilder.str(decoded['carrier']);
    const status     = CanonicalEventVariantBuilder.str(decoded['status']);
    const rawTimestamp = CanonicalEventVariantBuilder.str(decoded['epochRaw']);
    const address    = CanonicalEventVariantBuilder.str(decoded['address']);
    const phone      = CanonicalEventVariantBuilder.str(decoded['phone']);

    // Pre-resolved geo from RICH sources (JSON/YAML API with offline country-coder).
    // Present when the encoder set geoCountry / geoContinent / geoRegion on the record.
    // All three must be non-empty for the geo block to be valid; absent otherwise.
    const geoCountry   = CanonicalEventVariantBuilder.str(decoded['geoCountry']);
    const geoContinent = CanonicalEventVariantBuilder.str(decoded['geoContinent']);
    const geoRegion    = CanonicalEventVariantBuilder.str(decoded['geoRegion']);
    const preResolvedGeo = geoCountry.length > 0 && geoContinent.length > 0 && geoRegion.length > 0
      ? { 'country': geoCountry, 'continent': geoContinent, 'region': geoRegion }
      : undefined;

    return CanonicalEventVariantBuilder.resolveFromSourcePayloadHandler(payload.eventType)({
      envelope,
      decoded,
      sharedGeo: {
        scanSeq, latitude, longitude, ipAddress, localeTag, countryCode,
        legFromLat, legFromLng, originLat, originLng,
        destLat, destLng, carrier, status, rawTimestamp, address, phone,
      },
      preResolvedGeo,
    });
  }

  private static resolveFromSourcePayloadHandler(eventType: string): (ctx: FromSourcePayloadContext) => CanonicalEventVariant {
    const positionPingHandler = CanonicalEventVariantBuilder.fromSourcePayloadDispatch['position-ping'];
    const positionPingDefault = (ctx: FromSourcePayloadContext): CanonicalEventVariant => {
      const body: PositionPingEvent['body'] = {
        'scanSeq':      ctx.sharedGeo.scanSeq,
        'latitude':     ctx.sharedGeo.latitude,
        'longitude':    ctx.sharedGeo.longitude,
        'ipAddress':    ctx.sharedGeo.ipAddress,
        'localeTag':    ctx.sharedGeo.localeTag,
        'countryCode':  ctx.sharedGeo.countryCode,
        'legFromLat':   ctx.sharedGeo.legFromLat,
        'legFromLng':   ctx.sharedGeo.legFromLng,
        'originLat':    ctx.sharedGeo.originLat,
        'originLng':    ctx.sharedGeo.originLng,
        'destLat':      ctx.sharedGeo.destLat,
        'destLng':      ctx.sharedGeo.destLng,
        'carrier':      ctx.sharedGeo.carrier,
        'status':       ctx.sharedGeo.status,
        'rawTimestamp': ctx.sharedGeo.rawTimestamp.length > 0 ? ctx.sharedGeo.rawTimestamp : POSITION_PING_BODY_DEFAULT.rawTimestamp,
        'address':      ctx.sharedGeo.address,
        'phone':        ctx.sharedGeo.phone,
      };
      return { ...ctx.envelope, 'eventType': 'position-ping', 'body': body, ...(ctx.preResolvedGeo !== undefined && { 'geo': ctx.preResolvedGeo }) };
    };
    return CanonicalEventVariantBuilder.fromSourcePayloadDispatch[eventType] ?? positionPingHandler ?? positionPingDefault;
  }
}

GeoContext — geo-enrichment result

ts
import type { FromSchema } from 'json-schema-to-ts';

export const GeoContextSchema = {
  '$id': 'https://noocodec.dev/schemas/cartographer/GeoContext',
  '$schema': 'https://json-schema.org/draft/2020-12/schema',
  'type': 'object',
  'required': ['gridZone', 'country', 'continent', 'countries', 'region', 'hub', 'status', 'waterBodies', 'timezone', 'jurisdiction'],
  'properties': {
    'gridZone':   { 'type': 'string', 'minLength': 1 },
    'country':    { 'type': 'string', 'minLength': 1 },
    // Macro continent (from a real API) — the insights table buckets by this.
    'continent':  { 'type': 'string', 'minLength': 1 },
    'countries':  { 'type': 'array', 'items': { 'type': 'string' } },
    'region':     { 'type': 'string', 'minLength': 1 },
    'hub':        { 'type': 'string', 'minLength': 1 },
    'status':     { 'type': 'string', 'enum': ['land', 'water', 'coastal', 'unmapped'] },
    'waterBodies': { 'type': 'array', 'items': { 'type': 'string' } },
    'timezone':     { 'type': 'string', 'minLength': 1 },
    'jurisdiction': { 'type': 'string', 'enum': ['GDPR', 'UK-GDPR', 'CCPA', 'LGPD', 'APPI', 'baseline', 'international-waters'] },
  },
  'additionalProperties': false,
} as const;

export type GeoContext = FromSchema<typeof GeoContextSchema>;

CLI

bash
# Run with 200 journeys (live IP geolocation when network reachable):
npx tsx examples/the-cartographer/runCartographer.ts

# Force offline / recorded mode:
npx tsx examples/the-cartographer/runCartographer.ts --recorded

# Custom event count:
npx tsx examples/the-cartographer/runCartographer.ts --events 50
ts
import { CartographerState } from './CartographerState.ts';
import type { JourneyInsights, RegionInsights } from './CartographerState.ts';
import type { CartographerServices } from './CartographerServices.ts';
import { cartographerBundle, cartographerResumeBundle, cartographerWorkersBundle } from './dag.ts';
import { gdprComplianceBundle } from './embedded-dags/GdprComplianceDAG.ts';
import { GeoSourceResolveDAG } from './embedded-dags/GeoSourceResolveDAG.ts';
import { ingestSourceBundle } from './embedded-dags/IngestSourceDAG.ts';
import { orderEnrichmentBundle } from './embedded-dags/OrderEnrichmentDAG.ts';
import type { EnrichedShipment } from './entities/EnrichedShipment.ts';
import type { ConsoleLogger } from './logger/ConsoleLogger.ts';
import { ObservedCartographer } from './ObservedCartographer.ts';
import { normalizeSourcesPlugin } from './plugins/NormalizeSourcesPlugin.ts';
import { CartographerSourceIntake } from './nodes/sourceIntake.ts';
import type { DagonizerOptionsType } from '@studnicky/dagonizer';
import { GeoResolvers } from './services/GeoResolvers.ts';
import { ErrorRollup, type ErrorRollupType } from './errors/ErrorRollup.ts';

import { DAGError } from '@studnicky/dagonizer/errors';
import { StreamCursor } from '@studnicky/dagonizer/channels';
import { Signal } from '@studnicky/signal';

// ── Parse CLI args ────────────────────────────────────────────────────────────
let eventCount = 200;
let forceRecorded = false;
let useWorkers = process.env['CARTO_WORKERS'] === '1';
let useStreaming = process.env['CARTO_STREAM'] === '1';
let streamCount = 0;
const args = process.argv.slice(2);
for (let i = 0; i < args.length; i++) {
  if (args[i] === '--events' && args[i + 1] !== undefined) {
    const parsed = parseInt(args[i + 1] ?? '200', 10);
    if (!isNaN(parsed) && parsed > 0) eventCount = parsed;
  } else if (args[i] === '--recorded') {
    forceRecorded = true;
  } else if (args[i] === '--workers') {
    useWorkers = true;
  } else if (args[i] === '--stream') {
    useStreaming = true;
  } else if (args[i] === '--stream-count' && args[i + 1] !== undefined) {
    const parsed = parseInt(args[i + 1] ?? '0', 10);
    if (!isNaN(parsed) && parsed > 0) streamCount = parsed;
    i++;
  } else if (/^\d+$/.test(args[i] ?? '')) {
    const parsed = parseInt(args[i] ?? '200', 10);
    if (!isNaN(parsed) && parsed > 0) eventCount = parsed;
  }
}

// ── CLI utilities ─────────────────────────────────────────────────────────────

/**
 * AbortingCartographer: ObservedCartographer subclass for the resume scenario.
 *
 * Fires an AbortController after N scatter item completions (detected by
 * watching for `aggregate-event` nodes inside the `process-stream` scatter body).
 * Injection via constructor keeps the abort logic out of the main dispatcher.
 */
class AbortingCartographer extends ObservedCartographer {
  readonly #controller: AbortController;
  readonly #threshold: number;
  #count: number;

  constructor(options: DagonizerOptionsType, controller: AbortController, threshold: number) {
    super(options);
    this.#controller = controller;
    this.#threshold = threshold;
    this.#count = 0;
  }

  protected override onNodeEnd(
    nodeName: string,
    output: string | null,
    state: CartographerState,
    placementPath: readonly string[],
  ): void {
    super.onNodeEnd(nodeName, output, state, placementPath);
    // Count completions of aggregate-event inside the process-stream scatter.
    // aggregate-event is the last enrichment node before the scatter body terminal.
    if (nodeName === 'aggregate-event' && placementPath.includes('process-stream')) {
      if (++this.#count >= this.#threshold) {
        this.#controller.abort();
      }
    }
  }

  get signal(): AbortSignal {
    return this.#controller.signal;
  }
}

/** Fixed event count for the interrupted+resume run pair. */
const RESUME_EVENT_COUNT = 40;
/**
 * Number of scatter item completions (aggregate-event inside process-stream)
 * after which the interrupted run aborts. cartographerResumeDAG has no reservoir,
 * so items are dispatched one-at-a-time (ScatterWorkerPool path) and the abort
 * signal fires between pulls — giving a non-zero StreamCursor value.
 */
const ABORT_AFTER_ITEMS = 8;

/**
 * InsightsFingerprint: deterministic canonical digest of a regional insights Map.
 *
 * Sorts entries by region → country → hub and emits all numeric fields of each
 * RegionInsights plus the string keys. JSON.stringify over the sorted plain array
 * gives a stable string suitable for equality comparison.
 */
class InsightsFingerprint {
  private constructor() { /* static-only */ }

  static of(insights: Map<string, RegionInsights>): string {
    const rows = [...insights.values()].sort((a, b) => {
      const byRegion = a.region.localeCompare(b.region);
      if (byRegion !== 0) return byRegion;
      const byCountry = a.country.localeCompare(b.country);
      if (byCountry !== 0) return byCountry;
      return a.hub.localeCompare(b.hub);
    });
    const normalized = rows.map((r) => ({
      'region':                 r.region,
      'country':                r.country,
      'hub':                    r.hub,
      'deliveries':             r.deliveries,
      'exceptions':             r.exceptions,
      'onTimeCount':            r.onTimeCount,
      'lateCount':              r.lateCount,
      'totalSubtotalUsdMinor':  r.totalSubtotalUsdMinor,
      'totalShippingUsdMinor':  r.totalShippingUsdMinor,
      'totalDistanceKm':        r.totalDistanceKm,
      'totalDelayHours':        r.totalDelayHours,
      'consentValid':           r.consentValid,
      'consentMissing':         r.consentMissing,
      'consentExpired':         r.consentExpired,
      'sizeTierEnvelope':       r.sizeTierEnvelope,
      'sizeTierSmall':          r.sizeTierSmall,
      'sizeTierMedium':         r.sizeTierMedium,
      'sizeTierLarge':          r.sizeTierLarge,
      'sizeTierFreight':        r.sizeTierFreight,
      'shipmentCount':          r.shipmentCount,
    }));
    return JSON.stringify(normalized);
  }
}

/**
 * CartographerResumableScenario: self-contained abort→cursor→resume verification.
 *
 * Uses `cartographerResumeDAG` (no reservoir) so abort fires mid-scatter, leaving
 * acked items in the checkpoint and un-pulled items un-acked.
 *
 *   Baseline — Full streaming pass over all RESUME_EVENT_COUNT items (no abort).
 *              Produces the reference InsightsFingerprint.
 *   Step A   — Interrupted run: abort after ABORT_AFTER_ITEMS aggregate-event
 *              completions; read durable cursor from checkpoint.
 *   Step B   — Resume: restore from firstState.snapshot() (carries accumulator +
 *              checkpoint) and supply the remainder through CartographerSourceIntake.
 *              Assert cursor > 0 and resumeResult.cursor === null (completed).
 *   Proof    — Compare InsightsFingerprint of resumed state to baseline fingerprint.
 *              Equal → exactly-once; unequal → throw with full diff.
 */
class CartographerResumableScenario {
  private constructor() { /* static-only */ }

  /** Register cartographerResumeBundle bundles onto a fresh ObservedCartographer. */
  static #buildResumeDispatcher(services: CartographerServices): ObservedCartographer {
    const d = new ObservedCartographer({});
    d.registerBundle(GeoSourceResolveDAG.build(services.ipGeolocator, services.addressGeocoder));
    d.registerBundle(orderEnrichmentBundle);
    d.registerBundle(gdprComplianceBundle);
    d.registerPlugin(normalizeSourcesPlugin);
    d.registerBundle(ingestSourceBundle);
    d.registerBundle(cartographerResumeBundle);
    return d;
  }

  static async run(
    _dispatcher: ObservedCartographer,
    services: CartographerServices,
    logger: ConsoleLogger,
    _eventCount: number,
  ): Promise<void> {
    logger.info('CartographerResumableScenario', 'run', `Starting streamed-resume verification (${RESUME_EVENT_COUNT} events, abort after ${ABORT_AFTER_ITEMS})`);

    // ── Baseline: full streaming pass (no abort) ─────────────────────────────
    // Runs the same producer + same event count through the same DAG without
    // interruption. Produces the reference accumulator for the exactly-once proof.
    const baselineDispatcher = CartographerResumableScenario.#buildResumeDispatcher(services);
    const baselineState = new CartographerState();
    baselineState.useStreamingSource = true;
    baselineState.eventCount = RESUME_EVENT_COUNT;
    baselineState.streamCount = RESUME_EVENT_COUNT;
    await baselineDispatcher.execute('urn:noocodec:dag:cartographer-resume', baselineState);
    const baselineFingerprint = InsightsFingerprint.of(baselineState.insights);
    logger.info('CartographerResumableScenario', 'baseline', `Baseline streamed run folded ${baselineState.insights.size} region(s).`);

    // ── Step A: Interrupted run ──────────────────────────────────────────────
    // AbortingCartographer fires abort after ABORT_AFTER_ITEMS aggregate-event
    // completions inside process-stream. cartographerResumeDAG has no reservoir,
    // so the ScatterWorkerPool checks abort between item pulls — giving cursor > 0.
    const interruptAc = new AbortController();
    const abortingDispatcher = new AbortingCartographer({}, interruptAc, ABORT_AFTER_ITEMS);
    abortingDispatcher.registerBundle(GeoSourceResolveDAG.build(services.ipGeolocator, services.addressGeocoder));
    abortingDispatcher.registerBundle(orderEnrichmentBundle);
    abortingDispatcher.registerBundle(gdprComplianceBundle);
    abortingDispatcher.registerPlugin(normalizeSourcesPlugin);
    abortingDispatcher.registerBundle(ingestSourceBundle);
    abortingDispatcher.registerBundle(cartographerResumeBundle);

    const firstState = new CartographerState();
    firstState.useStreamingSource = true;
    firstState.eventCount = RESUME_EVENT_COUNT;
    firstState.streamCount = RESUME_EVENT_COUNT;

    let interruptedCursor: string | null = null;
    try {
      const interruptedResult = await abortingDispatcher.execute(
        'cartographer-resume', firstState, { 'signal': interruptAc.signal },
      );
      interruptedCursor = interruptedResult.cursor;
    } catch (err) {
      if (!(err instanceof DAGError && err.code === 'EXECUTION_ERROR')) throw err;
    }

    // Read the durable stream cursor from the interrupted checkpoint.
    const cursor = StreamCursor.resumeAfter(firstState, 'process-stream');
    logger.info(
      'CartographerResumableScenario', 'interrupted',
      `Interrupted after ${ABORT_AFTER_ITEMS} items. execution cursor='${String(interruptedCursor)}' stream cursor=${cursor}`,
    );

    process.stdout.write(`ASSERT cursor > 0: ${cursor > 0 ? 'PASS' : 'FAIL'} (cursor=${cursor})\n`);
    if (cursor === 0) {
      throw new Error('CartographerResumableScenario: cursor is 0 — checkpoint not preserved after abort');
    }

    // ── Step B: Resume ───────────────────────────────────────────────────────
    // Restore from the interrupted snapshot — this is the faithful cross-process
    // restart path: the partial insights accumulator AND the SCATTER_PROGRESS_KEY
    // checkpoint are both carried by CartographerState.restore(firstState.snapshot()).
    // Acked items (below the watermark) already contributed to state.insights and
    // are NOT replayed by the engine; the accumulator carry ensures their folds
    // survive. Un-acked items in the durable inbox are replayed by the engine.
    const resumeDispatcher = CartographerResumableScenario.#buildResumeDispatcher(services);

    const resumeState = CartographerState.restore(firstState.snapshot());
    resumeState.useStreamingSource = true;
    resumeState.eventCount = RESUME_EVENT_COUNT;
    resumeState.streamCount = RESUME_EVENT_COUNT;
    // Supply the remainder: the top-level intake gather is already complete in
    // the restored checkpoint, so resume enters process-stream directly.
    resumeState.sources = CartographerSourceIntake.mergedFor(resumeState, cursor);

    const resumeResult = await resumeDispatcher.resume('urn:noocodec:dag:cartographer-resume', resumeState, 'process-stream');

    logger.info(
      'CartographerResumableScenario', 'resume',
      `Resume complete. cursor=${String(resumeResult.cursor)} (expected null)`,
    );

    process.stdout.write(`ASSERT resume completed: ${resumeResult.cursor === null ? 'PASS' : 'FAIL'} (cursor=${String(resumeResult.cursor)})\n`);
    if (resumeResult.cursor !== null) {
      throw new Error(`CartographerResumableScenario: resume did not complete (cursor='${String(resumeResult.cursor)}')`);
    }

    // ── Exactly-once proof: compare resumed fingerprint to baseline ───────────
    // The fingerprint encodes ALL numeric fields for every region, sorted
    // deterministically. Equal → every acked fold was carried (not lost, not
    // double-counted); unequal → the accumulator carry is broken.
    const resumeFingerprint = InsightsFingerprint.of(resumeState.insights);
    const exactlyOnce = resumeFingerprint === baselineFingerprint;
    process.stdout.write(`ASSERT exactly-once (resume insights == baseline insights): ${exactlyOnce ? 'PASS' : 'FAIL'}\n`);
    if (!exactlyOnce) {
      throw new Error(
        `CartographerResumableScenario: exactly-once violated — resumed insights differ from baseline.\n` +
        `  baseline: ${baselineFingerprint}\n` +
        `  resumed:  ${resumeFingerprint}`,
      );
    }

    // ── Shipment-count cross-check ────────────────────────────────────────────
    // Grand total of shipmentCount across all regions must be identical between
    // the resumed run and the baseline (gross undercount / double-count guard).
    let baselineTotal = 0;
    for (const r of baselineState.insights.values()) baselineTotal += r.shipmentCount;
    let resumeTotal = 0;
    for (const r of resumeState.insights.values()) resumeTotal += r.shipmentCount;
    const countMatch = resumeTotal === baselineTotal;
    process.stdout.write(`ASSERT shipment-count (resume=${resumeTotal} == baseline=${baselineTotal}): ${countMatch ? 'PASS' : 'FAIL'}\n`);
    if (!countMatch) {
      throw new Error(
        `CartographerResumableScenario: shipment-count mismatch — resumed total (${resumeTotal}) != baseline (${baselineTotal})`,
      );
    }

    process.stdout.write('Streamed resume: COMPLETE. Exactly-once verified.\n');
  }
}

class CartographerCli {
  static async networkReachable(): Promise<boolean> {
    try {
      const signal = Signal.timeout(4000);
      const res = await fetch('https://freeipapi.com/api/json/8.8.8.8', {
        signal,
        'headers': { 'accept': 'application/json' },
      });
      return res.ok;
    } catch {
      return false;
    }
  }

  static fmtCoord(lat: number, lng: number): string {
    const ns = `${Math.abs(lat).toFixed(2)}${lat >= 0 ? 'N' : 'S'}`;
    const ew = `${Math.abs(lng).toFixed(2)}${lng >= 0 ? 'E' : 'W'}`;
    return `${ns} ${ew}`;
  }

  static printJourney(logger: ConsoleLogger, j: JourneyInsights): void {
    const km = Math.round(j.pathKm).toLocaleString('en-US');
    const elapsedH = Math.floor(j.elapsedHours);
    const elapsedM = Math.round((j.elapsedHours - elapsedH) * 60);
    logger.result(`${j.shipmentId}  (${j.scanCount} scans, ${j.timezones.length} timezone(s))`);
    for (const s of j.scans) {
      const time = s.localIso.slice(11, 16);
      const cum = `+${Math.round(s.legKm).toLocaleString('en-US')} km`;
      logger.result(
        `  ${time} ${s.utcOffset.padEnd(7)} ${s.status.padEnd(16)} ` +
        `${s.hub.slice(0, 18).padEnd(19)} ${CartographerCli.fmtCoord(s.lat, s.lng).padEnd(20)} ${cum}`,
      );
    }
    const tzCrossings = Math.max(0, j.offsets.length - 1);
    const jurisLabel = j.jurisdictions.length > 1 ? `${j.jurisdictions.join('')}` : j.jurisdictions[0] ?? 'baseline';
    const otLabel = j.delivered ? (j.onTime ? 'on-time' : `late ${j.delayHours}h`) : `in transit (${j.lastStatus})`;
    logger.result(`  journey: ${km} km · ${elapsedH}h${String(elapsedM).padStart(2, '0')}m elapsed · ${tzCrossings} tz crossing(s) · jurisdiction ${jurisLabel} · ${otLabel}`);
  }

  /**
   * Error-analysis section: total captured-exception count and a table of
   * `source · variant · count · sample-message`, ordered by descending count so the
   * dominant error source is first. This is the DAG-flow error collection made
   * visible — every captured exception folded by the gather is reported here.
   */
  static printErrorAnalysis(logger: ConsoleLogger, rollup: ErrorRollupType): void {
    logger.result('=== (e) Error Analysis — captured exceptions folded through the DAG ===\n');
    if (rollup.total === 0) {
      logger.result('  No exceptions captured this run. (A clean run — zero swallowed faults.)\n');
      return;
    }
    logger.result(`  Total captured exceptions: ${rollup.total.toLocaleString('en-US')}\n`);

    const COL_SOURCE  = 18;
    const COL_VARIANT = 14;
    const COL_COUNT   = 8;
    const hdr =
      'Source'.padEnd(COL_SOURCE) +
      'Variant'.padEnd(COL_VARIANT) +
      'Count'.padStart(COL_COUNT) +
      '  Sample message';
    logger.result(`  ${hdr}`);
    logger.result(`  ${'-'.repeat(hdr.length + 24)}`);
    for (const group of ErrorRollup.ranked(rollup)) {
      const sample = group.samples[0] ?? '';
      logger.result(
        `  ${group.source.slice(0, COL_SOURCE - 1).padEnd(COL_SOURCE)}` +
        `${group.variant.slice(0, COL_VARIANT - 1).padEnd(COL_VARIANT)}` +
        `${String(group.count).padStart(COL_COUNT)}  ${sample}`,
      );
    }
    logger.result('');
  }

  static printRedaction(logger: ConsoleLogger, label: string, rec: EnrichedShipment): void {
    logger.result(`  [${label}] ${rec.shipmentId}  jurisdiction=${rec.jurisdiction}  consent=${rec.consentStatus}`);
    logger.result(`    Name:    ${rec.redactedSample.recipientName}`);
    logger.result(`    Email:   ${rec.redactedSample.recipientEmail}`);
    logger.result(`    Phone:   ${rec.redactedSample.recipientPhone}`);
    logger.result(`    Coords:  ${CartographerCli.fmtCoord(rec.lat, rec.lng)}  ${rec.coordsCoarsened ? '(COARSENED to grid centroid)' : '(precise)'}`);
  }
}

// ── Geo backend selection: LIVE IP if a network is reachable, else RECORDED ────
// GPS reverse-geocode is ALWAYS offline (the `@rapideditor/country-coder` boundary
// dataset — deterministic, no network) — only the IP modality is a live API call.
// `useLive` selects the live freeipapi.com IP geolocator when reachable; otherwise
// (and with `--recorded`) the recorded IP fixture replays for a deterministic,
// offline run. The probe targets freeipapi (the only live modality).

const useLive = !forceRecorded && (await CartographerCli.networkReachable());
const services: CartographerServices = useLive ? GeoResolvers.live() : GeoResolvers.recorded();

// ── Worker container (only when --workers / CARTO_WORKERS=1) ─────────────────
// WorkerThreadContainer is only imported when the worker path is active. In
// tsx mode (in-process default) this branch is never reached.
//
// The registry module URL is resolved relative to this compiled file's location
// (examples/the-cartographer/dist/runCartographer.js) so the path resolves to
// examples/the-cartographer/dist/workers/eventPipelineRegistry.js — the compiled
// output of workers/eventPipelineRegistry.ts.
//
// Workers receive servicesConfig.useRecordedIp so they select the same IP backend
// as the parent (recorded when offline/--recorded, live when the parent is live).
let workerContainers: Array<{ destroy(): Promise<void> }> = [];

// ── Dispatcher ────────────────────────────────────────────────────────────────
// ObservedCartographer subclasses Dagonizer and wires every lifecycle hook to
// its internal ConsoleLogger — the sanctioned class-extension observability
// demonstration. Progress / status / diagnostic lines flow through the hooks;
// the final tabular report is routed through `dispatcher.logger.result(...)`.
let dispatcher: ObservedCartographer;

if (useWorkers) {
  // Dynamic import keeps WorkerThreadContainer out of the tsx bundle; workers
  // are only instantiated when the compiled path is active.
  const { WorkerThreadContainer } = await import('@studnicky/dagonizer-executor-node');
  const registryUrl = new URL('./workers/eventPipelineRegistry.js', import.meta.url).href;
  const cpuContainer = new WorkerThreadContainer({
    'registryModule':  registryUrl,
    'registryVersion': '1.0.0',
    'servicesConfig':  { 'useRecordedIp': !useLive },
    'poolSize':        4,
  });
  const ioContainer = new WorkerThreadContainer({
    'registryModule':  registryUrl,
    'registryVersion': '1.0.0',
    'servicesConfig':  { 'useRecordedIp': !useLive },
    'poolSize':        1,
  });
  workerContainers = [cpuContainer, ioContainer];

  // Workers mode: cartographerWorkersDAG delegates process-stream to `cpu` and
  // summarize-insights to `io`. The parent dispatcher still registers the full
  // bundle so DAG validation resolves every embedded reference.
  dispatcher = new ObservedCartographer({
    'containers': {
      'cpu': cpuContainer,
      'io':  ioContainer,
    },
  });
  // Sub-DAG bundles (needed for DAG validator; execution stays in the workers).
  dispatcher.registerBundle(GeoSourceResolveDAG.build(services.ipGeolocator, services.addressGeocoder));
  dispatcher.registerBundle(orderEnrichmentBundle);
  dispatcher.registerBundle(gdprComplianceBundle);
  dispatcher.registerPlugin(normalizeSourcesPlugin);
  // ingestSourceBundle owns all unique ingest nodes + all format sub-DAGs.
  dispatcher.registerBundle(ingestSourceBundle);
  // Top-level DAG (cartographerWorkersDAG binds process-stream to cpu and
  // summarize-insights to io).
  dispatcher.registerBundle(cartographerWorkersBundle);
} else {
  dispatcher = new ObservedCartographer({});
  dispatcher.registerBundle(GeoSourceResolveDAG.build(services.ipGeolocator, services.addressGeocoder));
  dispatcher.registerBundle(orderEnrichmentBundle);
  dispatcher.registerBundle(gdprComplianceBundle);
  dispatcher.registerPlugin(normalizeSourcesPlugin);
  // ingestSourceBundle owns all unique ingest nodes + all format sub-DAGs.
  dispatcher.registerBundle(ingestSourceBundle);
  dispatcher.registerBundle(cartographerBundle);
}

// The example's own logger, owned by the subclass. Display (the tabular report)
// goes through `logger.result(...)`; diagnostics flow from the hook overrides.
const logger = dispatcher.logger;

const state = new CartographerState();
state.eventCount = eventCount;
state.useStreamingSource = useStreaming;
state.streamCount = streamCount;

const executionMode = useWorkers
  ? 'WORKER THREADS (containers: cpu pool=4, io pool=1)'
  : useStreaming
    ? `IN-PROCESS + STREAMING SOURCE${streamCount > 0 ? ` (count=${streamCount})` : ''}`
    : 'IN-PROCESS (no container)';

// Run-configuration banner: status diagnostics → leveled info on the logger.
logger.info('runCartographer', 'banner', `${String(eventCount)} journeys -> multi-format sources -> fan-in -> streaming enrichment (concurrency=16)`);
logger.info('runCartographer', 'banner', `execution mode: ${executionMode}`);
logger.info('runCartographer', 'banner', `geo backend: offline country-coder reverse-geocode + ${useLive ? 'LIVE freeipapi.com IP geolocation' : 'RECORDED IP fixture replay (offline)'}`);

// ── Execute ───────────────────────────────────────────────────────────────────
const ac = new AbortController();
process.once('SIGINT', () => {
  logger.warn('runCartographer', 'onSigint', 'aborting pipeline');
  ac.abort();
});

let stageCount = 0;
let peakHeap = process.memoryUsage().heapUsed;
try {
  const execution = dispatcher.execute('urn:noocodec:dag:cartographer', state, { 'signal': ac.signal });
  for await (const stage of execution) {
    const cur = process.memoryUsage().heapUsed;
    if (cur > peakHeap) peakHeap = cur;
    if (!stage.skipped) {
      stageCount++;
      // Periodic progress heartbeat — leveled diagnostic, not raw stdout.
      // Per-node detail flows from the subclass hooks (onNodeStart/onNodeEnd).
      if (stageCount % 80 === 0) {
        logger.trace('runCartographer', 'progress', `${String(stageCount)} stages executed`);
      }
    }
  }
  await execution;
} catch (err) {
  if (err instanceof DAGError && err.code === 'EXECUTION_ERROR') {
    logger.fatal('runCartographer', 'execute', `execution failed: ${err.message}`);
    process.exit(1);
  }
  throw err;
}
logger.debug('runCartographer', 'execute', `pipeline drained: ${String(stageCount)} stages executed`);

// Bounded sample of enriched scans (cap 200). state.records is always empty
// in the streaming path (and in the insights-fold non-streaming path). All
// per-scan display sections iterate this sample — honest and memory-bounded.
const sampleProcessed = state.sampleRecords.filter((r) => r.shipmentId.length > 0);

// Total scans folded: exact sum from the insights accumulator (all scans,
// not sampled). The insights fold counts every event regardless of scatter
// concurrency, so this is authoritative.
let totalScans = 0;
for (const r of state.insights.values()) totalScans += r.shipmentCount;

// ── (0) Streaming source summary ──────────────────────────────────────────────
// The streaming topology decodes mixed formats inline per scan; there is no
// separate ingestion fan-in stage. Report what the accumulators know.
logger.result('=== (0) Streaming source — mixed formats decoded inline per scan ===\n');

// Per-event-type lane distribution derived from the bounded sample.
const byEventType = new Map<string, number>();
for (const r of sampleProcessed) {
  // The routing path encodes the event-type lane (e.g. "facility-scan/…").
  // Extract the first segment as a human-readable lane label.
  const lane = r.routing.path.split('/')[0] ?? r.routing.path;
  byEventType.set(lane, (byEventType.get(lane) ?? 0) + 1);
}

// Per-format distribution from the bounded sample routing path (the path
// encodes the lane name, not the wire format; use sampleRecords directly
// as a representative distribution indicator).
const distinctFormats = new Set<string>();
if (Array.isArray(state.sources)) {
  for (const item of state.sources) {
    distinctFormats.add(item.format);
  }
}
// Fall back to eventConfig format mix labels when sources is exhausted.
if (distinctFormats.size === 0) {
  for (const cfg of state.eventConfig) {
    for (const mix of cfg.formatMix) distinctFormats.add(mix.format);
  }
}

logger.result(`  Total scans folded (exact, from insights accumulator): ${totalScans.toLocaleString()}`);
logger.result(`  Continents resolved: ${state.insights.size}`);
logger.result(`  Wire formats in feed: ${distinctFormats.size > 0 ? [...distinctFormats].sort().join(', ') : 'mixed (json, csv, ndjson, yaml)'}`);
logger.result(`\n  Event-type lane distribution (from a representative sample of ${sampleProcessed.length} scans):`);
for (const lane of [...byEventType.keys()].sort()) {
  logger.result(`    ${lane.padEnd(28)} ${String(byEventType.get(lane) ?? 0).padStart(5)}`);
}
logger.result('');

// ── (e) Error analysis — the DAG-flow error collection made visible ───────────
// The geo transports and ingest parsers capture every caught exception into a
// GeoErrorRecord on state.errors; the insights-fold gather folds them into
// state.errorRollup (bounded, grouped by source+variant). Print the distribution.
CartographerCli.printErrorAnalysis(logger, state.errorRollup);

// ── (a) Normalization sample — a multi-zone, multi-scan journey ───────────────
// Prefer a journey that crosses >=2 timezones to show differing local offsets.
const multiZoneJourney =
  [...state.journeys.values()].find((j) => j.scanCount >= 3 && j.offsets.length >= 2)
  ?? [...state.journeys.values()].find((j) => j.scanCount >= 2 && j.offsets.length >= 2)
  ?? [...state.journeys.values()].find((j) => j.scanCount >= 2);

logger.result('=== (a) Normalization Sample — one journey, per-scan LOCAL time ===\n');
if (multiZoneJourney !== undefined) {
  logger.result(`${multiZoneJourney.shipmentId}  (${multiZoneJourney.scanCount} scans, ${multiZoneJourney.timezones.length} timezone(s), offsets: ${multiZoneJourney.offsets.join(', ')})`);
  for (const s of multiZoneJourney.scans) {
    const time = s.localIso.slice(11, 16);
    logger.result(
      `  seq ${s.scanSeq}  ${time} ${s.utcOffset.padEnd(7)} ${s.status.padEnd(16)} ` +
      `${s.hub.slice(0, 18).padEnd(19)} ${CartographerCli.fmtCoord(s.lat, s.lng).padEnd(20)} [${s.jurisdiction}]`,
    );
  }
}

// ── (b) Per-continent insights table ─────────────────────────────────────────
// Rolled up to the macro continent the real geo API resolved (~6–8 rows), plus a
// single maritime bucket — the precise locality/country stays on each journey scan.
logger.result('\n=== (b) Per-Continent Insights ===\n');

const COL_REGION = 34;
const COL_COUNT  = 7;
const COL_EXC    = 6;
const COL_ONTIME = 8;
const COL_REV    = 12;
const COL_SHIP   = 11;
const COL_DIST   = 10;

const hdr =
  'Continent'.padEnd(COL_REGION) +
  'Scans'.padStart(COL_COUNT) +
  'Exc'.padStart(COL_EXC) +
  'OnTime%'.padStart(COL_ONTIME) +
  'Rev $USD'.padStart(COL_REV) +
  'Ship $USD'.padStart(COL_SHIP) +
  'Dist km'.padStart(COL_DIST);
logger.result(hdr);
logger.result('-'.repeat(hdr.length));

const sortedRegions = [...state.insights.values()].sort((a, b) => a.region.localeCompare(b.region));
for (const r of sortedRegions) {
  const total = r.onTimeCount + r.lateCount;
  const onTimePct = total > 0 ? Math.round((r.onTimeCount / total) * 100) : 0;
  const revUsd  = (r.totalSubtotalUsdMinor / 100).toFixed(0);
  const shipUsd = (r.totalShippingUsdMinor / 100).toFixed(0);
  const distKm  = r.totalDistanceKm > 0 ? Math.round(r.totalDistanceKm / r.shipmentCount).toString() : '0';
  logger.result(
    r.region.slice(0, COL_REGION - 1).padEnd(COL_REGION) +
    String(r.shipmentCount).padStart(COL_COUNT) +
    String(r.exceptions).padStart(COL_EXC) +
    `${onTimePct}%`.padStart(COL_ONTIME) +
    `$${revUsd}`.padStart(COL_REV) +
    `$${shipUsd}`.padStart(COL_SHIP) +
    `${distKm}`.padStart(COL_DIST),
  );
}
logger.result(`\nTotal scans folded: ${totalScans.toLocaleString()} · Journeys sampled: ${state.journeys.size}`);

// ── (b2) SOURCE-MODEL ROUTING VIEW (the thesis made tangible — §B0.7c) ──────────
// Each clone records its own RAN/SKIPPED decisions on the enriched record; the
// gather appends each to sampleRecords (bounded FIFO, cap 200). The totals here
// are computed over that representative sample — honest because the sample is a
// cross-section of all event types and routing paths.
//
// Node cost model (the nodes a branch runs/skips per event):
//   geo-lookup chain : validate-coords + geo-grid + geo-context = 3 nodes
//                      (skip path runs apply-geo = 1 node → 2 avoided per skip)
//   order enrichment : enrich-pricing + enrich-shipping + enrich-eta = 3 nodes
//   redaction sub-DAG: consent-gate + classify-pii + redact-pii = 3 nodes
//                      (skip path bypasses all 3 directly → 3 avoided)
const GEO_CHAIN_NODES = 3;        // validate-coords, geo-grid, geo-context
const GEO_SKIP_ADAPTER = 1;       // apply-geo
const ORDER_ENRICH_NODES = 3;     // pricing, shipping, eta
const REDACTION_NODES = 3;        // consent-gate, classify-pii, redact-pii
const REDACTION_SKIP_ADAPTER = 0; // no intermediate node on skip path

let geoRun = 0, geoSkip = 0, redRun = 0, redSkip = 0, priceSkip = 0, etaSkip = 0;
let coldRun = 0, customsRun = 0;
// Source-model tally
let modelCoords = 0, modelLocale = 0, modelCode = 0, modelIp = 0, modelNone = 0;
let coordsPlusIp = 0, secondaryLookupFired = 0;
let ipgeoRun = 0, ipgeoSkip = 0;
let actualNodes = 0, naiveNodes = 0;
const pathCounts = new Map<string, number>();
for (const r of sampleProcessed) {
  const rt = r.routing;
  if (rt.geoLookupRun) geoRun++;
  if (rt.geoLookupSkipped) geoSkip++;
  if (rt.ipGeolocateRun) ipgeoRun++;
  if (rt.ipGeolocateSkipped) ipgeoSkip++;
  if (rt.redactionRun) redRun++;
  if (rt.redactionSkipped) redSkip++;
  if (rt.pricingSkipped) priceSkip++;
  if (rt.etaSkipped) etaSkip++;
  if (rt.coldChainRun) coldRun++;
  if (rt.customsDwellRun) customsRun++;
  // Source-model tally
  if (rt.geoSourceModel === 'coords') modelCoords++;
  else if (rt.geoSourceModel === 'locale') modelLocale++;
  else if (rt.geoSourceModel === 'code') modelCode++;
  else if (rt.geoSourceModel === 'ip') modelIp++;
  else modelNone++;
  if (rt.geoModalities.includes('ip') && (rt.geoModalities.includes('coords') || rt.geoModalities.includes('geohash'))) coordsPlusIp++;
  if (rt.geoSecondaryLookupUsed) secondaryLookupFired++;
  pathCounts.set(rt.path, (pathCounts.get(rt.path) ?? 0) + 1);

  naiveNodes += GEO_CHAIN_NODES + ORDER_ENRICH_NODES + REDACTION_NODES;
  actualNodes += rt.geoLookupRun ? GEO_CHAIN_NODES : GEO_SKIP_ADAPTER;
  if (rt.pricingRun) actualNodes += ORDER_ENRICH_NODES;
  actualNodes += rt.redactionRun ? REDACTION_NODES : REDACTION_SKIP_ADAPTER;
}
const sampleTotal = sampleProcessed.length;
class Percent {
  private constructor() { /* static-only */ }
  static of(n: number, base: number): string { return base > 0 ? `${Math.round((n / base) * 100)}%` : '0%'; }
}
const skippedNodes = naiveNodes - actualNodes;
const redactionPassesAvoided = redSkip;
const pricingEtaAvoided = priceSkip * ORDER_ENRICH_NODES;

logger.result('\n=== (b2) Source-Model Routing — from a bounded sample of recent scans ===\n');
logger.result(`  Sample size: ${sampleTotal} scans (representative bounded FIFO, cap 200)\n`);
logger.result(`  HEADLINE: deterministic routing skipped ${skippedNodes.toLocaleString('en-US')} node-executions in sample ` +
  `(~${Percent.of(skippedNodes, naiveNodes)} of the ${naiveNodes.toLocaleString('en-US')} always-run maximum).\n`);
logger.result('  Geo source-model distribution (from classify-geo-source):');
logger.result(`    • coords (lat/lng present):       ${String(modelCoords).padStart(5)}`);
logger.result(`    • code  (ISO-2 country code):     ${String(modelCode).padStart(5)}`);
logger.result(`    • locale (BCP-47 tag):            ${String(modelLocale).padStart(5)}`);
logger.result(`    • ip   (gateway IP only):         ${String(modelIp).padStart(5)}`);
logger.result(`    • none (no signal):               ${String(modelNone).padStart(5)}`);
logger.result('');
logger.result(`  coords+IP enriched (dual modality): ${coordsPlusIp}`);
logger.result(`  CoordTimezone secondary lookup fired: ${secondaryLookupFired}`);
logger.result('');
logger.result(`  geo-lookup:  RAN ${geoRun}  ·  SKIPPED ${geoSkip} (${Percent.of(geoSkip, sampleTotal)} — source already resolved → geo sub-DAG avoided)`);
logger.result(`  ip-geolocate (freeipapi.com): RAN ${ipgeoRun}  ·  SKIPPED ${ipgeoSkip}`);
logger.result(`  redaction:   RAN ${redRun}  ·  SKIPPED ${redSkip} (${Percent.of(redSkip, sampleTotal)} — no PII / not required → redaction sub-DAG bypassed)`);
logger.result(`  pricing+eta: RAN ${sampleTotal - priceSkip}  ·  SKIPPED ${priceSkip} (${Percent.of(priceSkip, sampleTotal)} — non-order event types carry no basket/delivery)`);
logger.result(`  per-event-type lanes: ${[...pathCounts.entries()].sort().map(([p, n]) => `${p}=${n}`).join('  ')}`);
logger.result(`  cold-chain-check RAN ${coldRun} (sensor lane only) · customs-dwell RAN ${customsRun} (customs lane only)`);
logger.result('\n  Compute avoided in sample:');
logger.result(`${redactionPassesAvoided.toLocaleString('en-US')} redaction passes avoided`);
logger.result(`${pricingEtaAvoided.toLocaleString('en-US')} pricing/shipping/ETA node-executions avoided — don't price a position ping.`);

// ── (c) Per-journey summaries (a few) ─────────────────────────────────────────
logger.result('\n=== (c) Per-Journey Summaries ===\n');
const journeysSorted = [...state.journeys.values()].sort((a, b) => b.scanCount - a.scanCount);
// Show a few: one multi-tz, one multi-jurisdiction, one delivered.
const shown = new Set<string>();
const picks: JourneyInsights[] = [];
const multiTz = journeysSorted.find((j) => j.offsets.length >= 2);
if (multiTz !== undefined) { picks.push(multiTz); shown.add(multiTz.shipmentId); }
const multiJuris = journeysSorted.find((j) => j.jurisdictions.length >= 2 && !shown.has(j.shipmentId));
if (multiJuris !== undefined) { picks.push(multiJuris); shown.add(multiJuris.shipmentId); }
const deliveredJourney = journeysSorted.find((j) => j.delivered && !shown.has(j.shipmentId));
if (deliveredJourney !== undefined) { picks.push(deliveredJourney); shown.add(deliveredJourney.shipmentId); }
for (const j of picks) {
  CartographerCli.printJourney(logger, j);
  logger.result('');
}

const tzCrossingJourneys = [...state.journeys.values()].filter((j) => j.offsets.length >= 2).length;
const jurisChangeJourneys = [...state.journeys.values()].filter((j) => j.jurisdictions.length >= 2).length;
logger.result(`Journeys crossing >=2 timezones: ${tzCrossingJourneys}`);
logger.result(`Journeys changing jurisdiction mid-path: ${jurisChangeJourneys}`);

// ── (d) Location-driven redaction comparison ──────────────────────────────────
// Drawn from the bounded sample (cap 200) — sufficient to find representative
// strict-jurisdiction and baseline records.
const strictRecord = sampleProcessed.find(
  (r) => r.coordsCoarsened && (r.jurisdiction === 'GDPR' || r.jurisdiction === 'UK-GDPR' || r.jurisdiction === 'LGPD'),
) ?? sampleProcessed.find((r) => r.coordsCoarsened);
const baselineRecord = sampleProcessed.find(
  (r) => !r.coordsCoarsened && r.jurisdiction === 'baseline' && r.consentStatus === 'valid',
) ?? sampleProcessed.find((r) => !r.coordsCoarsened);

logger.result('\n=== (d) Location-Driven Redaction (strict vs baseline) ===\n');
if (strictRecord !== undefined) CartographerCli.printRedaction(logger, 'strict', strictRecord);
if (baselineRecord !== undefined) {
  logger.result('');
  CartographerCli.printRedaction(logger, 'baseline', baselineRecord);
}

logger.result(`\nDone. ${state.insights.size} continent(s), ${state.journeys.size} journey(s). No Date.now. No Math.random.`);
logger.result(`Peak heap: ${Math.round(peakHeap / 1048576)} MB · scans folded: ${totalScans.toLocaleString()} · journeys sampled: ${state.journeys.size} · sampleRecords: ${state.sampleRecords.length}`);
logger.result(`Execution mode: ${executionMode}\n`);

// ── Streamed resume verification (--stream only) ──────────────────────────────
// Runs the three-phase abort→cursor→resume scenario to verify exactly-once
// delivery across a genuine interrupt. Only runs when --stream is passed so it
// does not add latency to the default in-process array path.
if (useStreaming) {
  await CartographerResumableScenario.run(dispatcher, services, logger, eventCount);
}

// Release worker pools so the process exits cleanly.
for (const container of workerContainers) {
  await container.destroy();
}

Details for Nerds

The thesis

Data orchestration = the same engine. LLM-agent workflows and deterministic ETL pipelines are both DAGs of typed nodes with state. The engine does not know or care whether a node calls an LLM, decodes CSV, or runs a haversine formula.

The Cartographer makes the value of the DAG concrete: deterministic conditional routing skips unnecessary work. A position-ping that already carries resolved geo never touches the geo-resolution sub-DAG. An event with no PII never touches the GDPR redaction sub-DAG. The savings are visible in the routing table.

Offline geo resolution

Coords resolution uses two offline primitives — no HTTP, no key, deterministic, identical in Node 18+ and the browser:

  • GeohashTzMap — a base64-embedded binary geohash→timezone lookup table. The primary fast path: a single table scan resolves lat/lng to an IANA timezone with no network call.
  • CoordTimezonetz-lookup + @rapideditor/country-coder. The browser-safe default path for border regions and gaps where the geohash table is ambiguous. CoordTimezone guards the RangeError that out-of-range coords would otherwise raise: when a coord pair falls outside all known boundaries, resolution degrades to an empty timezone/country rather than throwing, and the event continues through the pipeline at baseline.

Locale and code resolution are also fully offline (BCP-47 → IANA via LocaleTimezone; ISO-2 → timezone via CountryLocale). The only live network call in the geo path is IP geolocation (freeipapi.com, CORS-enabled, no key), or committed fixture replay in the smoke tests.

ts
/**
 * CoordTimezone: browser-safe WGS-84 coordinate → IANA timezone + ISO country.
 *
 * Uses tz-lookup (nearest-neighbour IANA zone, browser-safe) for the timezone
 * and @rapideditor/country-coder for the ISO 3166-1 alpha-2 country code.
 *
 * Browser-safe: no node:fs, no node:path, no geo-tz, no Buffer.
 *
 * @module
 */
import tzlookup from 'tz-lookup';
import { iso1A2Code } from '@rapideditor/country-coder';

export class CoordTimezone {
  public static resolve(latitude: number, longitude: number): { timezone: string; country: string } {
    let timezone: string;
    try {
      timezone = tzlookup(latitude, longitude);
    } catch {
      timezone = '';
    }

    const countryCode = iso1A2Code([longitude, latitude], { level: 'country' });
    const country = countryCode ?? '';

    return { timezone: timezone, country: country };
  }
}

Read these next when you want to connect Cartographer behavior to scatter, embedded DAGs, workers, streaming, and plugin-defined reusable flows.

Cartographer Feature Map

These numbered examples are the small-form counterparts to Cartographer behavior:

ExamplePrinciple in the runnable Cartographer
Example 04C: Container-Bound Scatterprocess-stream is a scatter placement with a container role; the example page isolates the worker-bound body shape.
Example 12: Worker ContainersThe stream-event body DAG runs through the same DagContainerInterface seam when container roles are bound.
Example 13: Multi-Backend Rolesprocess-stream binds to cpu and summarize-insights binds to io in the browser Cartographer runner while the parent DAG stays JSON-LD.
Example 14: Gather StrategiesCartographer’s InsightsFoldGather and first-class geo-weighted-fusion gather show scatter-local folds and embedded-producer fan-in.
Example 15: Incremental GatherThe insights panel updates through incremental fold semantics rather than waiting for a final batch merge.
Example 16: Scatter ResumeThe durable-inbox model is the checkpoint substrate for long-running stream scatters.
Example 17: Async Scatter Sourceseed can provide sources as an async stream; bounded scatter pulls only as capacity opens.
Example 27: Runtime DAG DispatchDynamic DagReference dispatch belongs here if hierarchical route expansion enters the demo.
Example 33: Plugin-Defined DAGsPlugin packaging belongs here for normalization pipelines (NormalizeCsvDAG, NormalizeJsonDAG, etc.) so plugins and embedded DAGs stay one interface.
Examples 34-36: Streaming SubstrateIntake stream assembly, resumable cursors, and DagStreamProducer are the substrate beneath Cartographer’s event stream.

Watched over by the Order of Dagon.