diff --git a/docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md b/docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md new file mode 100644 index 0000000..3c2c1b1 --- /dev/null +++ b/docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md @@ -0,0 +1,365 @@ +# Port Identity Corpus Audit — 2026-08-24 + +**Branch audited**: `develop` +**HEAD**: `868325a` (*Merge pull request #55 from FHoffarth/feature/public-deck-geometry-review-workspace-v1*) +**Scope**: `knowledge/ports/` and every consumer that reads it +**Method**: corpus-wide distinct-value analysis, followed by generator-source confirmation +**Status**: findings confirmed against generator source; remediation proposed in ADR-0006 + +--- + +## 0. Why this audit replaced the planned sprint + +The commissioned work was a port-by-port reconciliation sprint: audit a sample +of ports, downgrade unsupported precision, reconcile external research. + +That plan could not have found the defect described here. Every +`identity.json` file in the repository is individually well-formed and +individually plausible. Barcelona reads like researched data. So does Hamburg. +So does Singapore. The defect is invisible at file scope and only appears in +the **distribution across the corpus** — which is why a sampling audit of eight +ports would have returned a clean bill of health for a corpus in which every +trust-bearing field is a constant. + +**Generalisable lesson:** a machine-readable corpus should be audited by +scanning it, not by reading a sample of it. Sampling answers "is this file +plausible?" Scanning answers "is this corpus data?" Only the second question +detects generator output. + +--- + +## 1. Corpus inventory + +| Measure | Value | +|---|---| +| Port directories under `knowledge/ports/` | 119 | +| `identity.json` files | 119 | +| Total JSON files in tree | 161 | +| Directories with `identity.json` only | 113 | +| Directories with the 8-file rich layout | 6 | +| Distinct file layouts | 2 | + +The six rich-layout ports are **Barcelona, Genoa, Marseille, Messina, Naples, +Valletta**, each carrying `emergency.json`, `identity.json`, `medical.json`, +`port.json`, `sustainability.json`, `terminals.json`, `transport.json`, +`weather.json`. + +--- + +## 2. Principal finding — the identity layer is template output + +Across all 119 ports, every trust-bearing field resolves to a single constant +or to a two-valued split: + +| Field | Distinct values across 119 ports | +|---|---| +| `timezone` | `"UTC"` — 119/119 | +| `sources[].field` | `"all"` — 119/119 | +| `sources[].source_id` | `"src:official-port-authority"` — 119/119 | +| `sources[].trust_level` | `"OFFICIAL"` — 119/119 | +| `sources[].retrieved_at` | `2026-08-16T12:00:00Z` — 119/119 | +| `terminals[].walking_time_min` | `10` — 119/119 | +| `terminals[].step_free_access` | `true` — 119/119 | +| `logistics.card_acceptance_pct` | `98` — 119/119 | +| terminals per port | `1` — 119/119 | +| `terminals[].distance_to_city_center_m` | `500` (101) / `800` (18) | +| `terminals[].gangway_deck_default` | `5` (108) / `2` (11) | +| `terminals[].berths` | 2 synthetic entries (101) / 1 (18) | +| `negative_intelligence` | two templates, 101/18 split | + +There is no third value anywhere in the corpus for any of these fields. + +### 2.1 The 101/18 split explained + +The split is not a data property. It is **two generators**, each with its own +hardcoded template: + +| Generator | Ports | Fingerprint | +|---|---|---| +| `tools/mass_populate_knowledge.py` (~L170–205) | 101 | `distance_to_city_center_m: 500`; `berths: ["{Slug} Berth 1", "{Slug} Berth 2"]`; `gangway_deck_default: 5 if "River" not in region else 2`; `negative_intelligence[0] = f"Check terminal berth assignment upon morning arrival in {name}."` | +| `tools/populate_classes_and_ports.py` (~L52–86) | 18 | `distance_to_city_center_m: 800`; `berths: ["{Slug} Pier 1"]`; `gangway_deck_default: 5`; `negative_intelligence[0] = f"Verify pier location in {name}."` | + +The `gangway_deck_default` 108/11 split is a nested conditional inside +generator A: eleven river ports carry `2`, everything else `5`. + +Both generators emit the identical blanket source record: + +```python +"sources": [ + {"field": "all", "source_id": "src:official-port-authority", + "trust_level": "OFFICIAL", "retrieved_at": "2026-08-16T12:00:00Z"} +] +``` + +**These values are synthetic/template-derived and carry no field-level +evidence.** This is not inferred from the distribution — the generator source +is in the repository and is quoted above. The distribution raised the +question; the generator source answered it. + +--- + +## 3. Provenance laundering + +The blanket source record is the mechanism by which unsourced generator output +acquired an authoritative appearance. Three independent defects compound: + +1. **`field: "all"`** — a source covering every field attests no field in + particular. It cannot establish provenance for `card_acceptance_pct` or for + anything else. +2. **`source_id: "src:official-port-authority"`** — this names a *category of + authority*, not a retrievable document. No artifact, no URL, no content + address. There is nothing behind it to fetch or verify. +3. **`trust_level: "OFFICIAL"`** — the corpus's highest trust label, applied + uniformly by a generator to values the generator itself invented. + +`retrieved_at` is identical to the second across all 119 ports, which is not a +possible outcome of 119 retrievals. + +This is the P0-A/P0-B anti-pattern in its purest observed form: unsourced +values inheriting an authoritative provenance stamp. It is more severe than +the earlier instances, because here the values never had a source at any point +— the stamp was applied by a generator to content it fabricated in the same +statement. + +--- + +## 4. Passenger-facing risk + +Ranked by consequence to a traveller. + +### 4.1 `timezone: "UTC"` on all 119 ports — SEVERE + +All-aboard time is computed from this field. The corpus spans Reykjavík to +Sydney; not one port is correctly UTC in practice for local operations +(Barcelona is `Europe/Madrid`). A passenger acting on a UTC-derived all-aboard +time in Barcelona in summer is wrong by two hours in the direction that misses +the ship. + +### 4.2 `logistics.emergency_phone` — SEVERE + +Not in the original quarantine scope; discovered during consumer analysis and +added. The generators derive this from a country allow-list with an +else-branch fallback: + +```python +"emergency_phone": "112" if p["country"] not in ["United States", "Puerto Rico"] else "911" +``` + +Distribution: `112` (91 ports), `911` (23), `999` (5). The else-branch +misroutes every country outside the allow-list. Confirmed incorrect values +include: + +| Port | Country | Stored | Actual | +|---|---|---|---| +| `costa-maya`, `cozumel` | Mexico | `112` | `911` | +| `bridgetown` | Barbados | `112` | `511` / `911` | +| `grand-cayman` | Cayman Islands | `112` | `911` | +| `haifa` | Israel | `112` | `100` / `101` / `102` | + +A wrong emergency number published under `trust_level: OFFICIAL` is the most +directly harmful fact in the corpus. Phase 2F (fail-closed on passenger-facing +claims) applies without qualification. + +### 4.3 `logistics.currency` — MODERATE + +31 of 119 ports carry the literal string `"Local"`, the generator's +else-branch. This is a non-value occupying a field a passenger would read. + +### 4.4 Synthetic precision — MODERATE + +`walking_time_min: 10`, `distance_to_city_center_m: 500/800`, +`card_acceptance_pct: 98`, `step_free_access: true`. Each is actionable and +each is invented. `step_free_access: true` corpus-wide is an accessibility +claim asserted for 119 ports without a single observation, and is the one most +likely to strand a wheelchair user. + +--- + +## 5. Duplicate UN/LOCODE entity pairs + +Two LOCODEs appear twice, indicating either duplicate directories for one port +or a genuine entity-identity question: + +| LOCODE | Directories | +|---|---| +| `USPEF` | `fort-lauderdale`, `port-everglades` | +| `ITTRS` | `trieste`, `venice-trieste` | + +Both pairs are plausibly the same physical port under two slugs — the same +class of question as New York vs. Bayonne, but already live in the repository. +All 119 LOCODEs are syntactically well-formed (5 chars, uppercase +alphanumeric); none has been validated against the UNECE list. + +**Not resolved in this audit.** Entity identity is an ontology decision +requiring its own ADR, not a cleanup edit. + +--- + +## 6. The six rich-layout ports + +These carry a **second, incompatible provenance model**: + +```json +"provenance": { "source_artifact": "CRUISE_PORT_INTELLIGENCE_PROFILE_WEST_MED_2026" } +``` + +plus per-item `"source"` (a prose authority name) and `"provenance"` (an opaque +string such as `"BCN-PA-TERM-A"`). Neither resolves to a content-addressed +artifact. `CRUISE_PORT_INTELLIGENCE_PROFILE_WEST_MED_2026` is a name, not an +address. + +**However**: this content does not exhibit template fingerprints. Values vary +per port, are specific and checkable (named hospitals with addresses and phone +numbers, named metro lines, named terminal operators), and read as +hand-researched. Its provenance model is inadequate; its *content* is not +demonstrated to be synthetic and **must not be assumed invalid merely because +`identity.json` in the same directory is**. + +### 6.1 `identity.json` vs `port.json` contradictions + +| Port | terminals in `identity.json` | in `port.json` | in `terminals.json` | `un_locode` | `unlocode` | +|---|---|---|---|---|---| +| barcelona | 1 | 8 | 8 | `ESBCN` | `ES-BCN` | +| genoa | 1 | 3 | 3 | `ITGOA` | `IT-GOA` | +| marseille | 1 | 2 | 2 | `FRMRS` | `FR-MRS` | +| messina | 1 | 1 | 1 | `ITMSN` | `IT-MSN` | +| naples | 1 | 3 | 3 | `ITNAP` | `IT-NAP` | +| valletta | 1 | 2 | 2 | `MTMLA` | `MT-MLA` | + +Two divergences: the single-terminal count is generator output contradicting +researched data, and the LOCODE is stored under two field names in two formats +in the same directory. + +--- + +## 7. Unexpected findings + +### U-1 — The frontend bridge is an independent second source of synthetic values + +`tools/generate_frontend_bridge.py` (~L130–170) does **not** read these values +from the knowledge layer. It hardcodes them inline at generation time: + +```python +"berths": ["Berth 1", "Berth 2"], +"gangwayDeckDefault": 5, +"distanceToCenterM": 500, +"walkingTimeMin": 10, +"cardAcceptancePct": 98, +"officialSource": { + "authority": f"{name} Port Authority", + "url": "https://www.timonelo.com", + "trustLevel": "OFFICIAL", +}, +``` + +Three consequences: + +1. **Quarantining `identity.json` does not stop the frontend publishing these + values.** `frontend/src/generated/ports.ts` will continue to carry + `walkingTimeMin: 10` for all 119 ports regardless of the knowledge layer. +2. `officialSource.url` is **Timonelo's own domain**, presented as the port + authority's official source under `trustLevel: "OFFICIAL"`. The authority + name is manufactured by string interpolation. +3. `locode = p.get("un_locode", "ITGOA")` — any port missing a LOCODE + **silently becomes Genoa**. Same pattern for `country` → `"Italy"` and + `region` → `"Mediterranean"`. + +This is the `fleet.ts` failure mode again: a generated frontend artifact +carrying values the knowledge layer does not support. It is arguably the more +serious of the two, because it bypasses the knowledge layer entirely and +therefore cannot be fixed by any amount of knowledge-layer governance. + +**Not fixed in this patch.** The `PortData` TypeScript interface declares these +fields non-optional, so removing them is a frontend contract change requiring +a design decision about how the UI renders UNKNOWN. That is not a mechanical +edit. + +### U-2 — Committed generated artifacts are already stale on `develop` + +`data/cruise_intelligence_db.json` and `data/cruise_knowledge_graph.json` do +not match what `develop`'s own knowledge layer compiles to. Verified on a +pristine `HEAD` checkout with no modifications: regeneration produces a +~20,000-line diff, concentrated in `ship:msc-bellissima` and +`ship:msc-meraviglia` cabin attributes. + +Regeneration is **deterministic** (byte-identical across repeated runs), so +this is genuine drift, not nondeterminism. + +**Consequence for this patch:** `data/` is deliberately excluded. Regenerating +would mix ~20k lines of pre-existing unrelated drift into a port quarantine +diff, making both unreviewable. Regeneration must be a separate, deliberate +change once the drift is understood. + +--- + +## 8. Remediation applied + +See ADR-0006. Summary: `knowledge/ports/*/identity.json` × 119, synthetic +fields nulled or emptied, blanket source records removed. Entity identity +fields (`slug`, `name`, `un_locode`, `country`, `region`, `coordinates`, +`terminals[].name`) preserved unchanged and **not promoted** to trusted facts. + +Enforcement: `tests/test_port_identity_quarantine.py`, 13 corpus-wide +invariants. These are distribution-based rather than per-file, because a +per-file assertion cannot distinguish researched data from template output. + +--- + +## 9. Explicit UNKNOWNs and unresolved items + +| # | Item | Status | +|---|---|---| +| K1 | Correct IANA timezone for all 119 ports | UNKNOWN — nulled, needs sourced per-port value | +| K2 | Correct emergency number for all 119 ports | UNKNOWN — nulled; **passenger-safety priority** | +| K3 | Walking time / centre distance / step-free access | UNKNOWN — no evidence exists for any port | +| K4 | Card acceptance rate | UNKNOWN — questionable as a knowledge-layer field at all | +| K5 | Real terminal and berth inventories | UNKNOWN for 113 ports; 6 rich ports have candidate data | +| K6 | Validity of all 119 UN/LOCODEs | UNVALIDATED — syntactically well-formed, never checked against UNECE | +| K7 | `USPEF` and `ITTRS` duplicate pairs | UNRESOLVED — ontology decision, needs its own ADR | +| K8 | Provenance model for the 6 rich ports | UNRESOLVED — separate audit required | +| K9 | Frontend bridge hardcoded values (U-1) | UNRESOLVED — frontend contract decision required | +| K10 | `data/` drift (U-2) | UNRESOLVED — cause not investigated | +| K11 | Generators still present and will re-emit templates if run | MITIGATED by tests, not removed | + +--- + +## Appendix A — Machine-readable finding summary + +```json +{ + "audit_date": "2026-08-24", + "branch": "develop", + "head_sha": "868325a", + "corpus": { + "port_directories": 119, + "identity_files": 119, + "rich_layout_ports": ["barcelona", "genoa", "marseille", "messina", "naples", "valletta"] + }, + "template_constants": { + "timezone": {"UTC": 119}, + "walking_time_min": {"10": 119}, + "card_acceptance_pct": {"98": 119}, + "step_free_access": {"true": 119}, + "terminals_per_port": {"1": 119}, + "distance_to_city_center_m": {"500": 101, "800": 18}, + "gangway_deck_default": {"5": 108, "2": 11}, + "sources_field": {"all": 119}, + "sources_source_id": {"src:official-port-authority": 119}, + "sources_trust_level": {"OFFICIAL": 119}, + "sources_retrieved_at": {"2026-08-16T12:00:00Z": 119} + }, + "generators": [ + {"path": "tools/mass_populate_knowledge.py", "ports": 101, "distance_m": 500}, + {"path": "tools/populate_classes_and_ports.py", "ports": 18, "distance_m": 800} + ], + "duplicate_locodes": { + "USPEF": ["fort-lauderdale", "port-everglades"], + "ITTRS": ["trieste", "venice-trieste"] + }, + "emergency_phone_distribution": {"112": 91, "911": 23, "999": 5}, + "currency_distribution": { + "EUR": 55, "Local": 31, "USD": 17, "NOK": 8, "MXN": 4, "GBP": 2, "SGD": 1, "AUD": 1 + }, + "unexpected_findings": ["U-1 frontend bridge hardcodes values", "U-2 data/ drift on develop"] +} +``` diff --git a/docs/adr/ADR-0006.md b/docs/adr/ADR-0006.md new file mode 100644 index 0000000..77c6e6b --- /dev/null +++ b/docs/adr/ADR-0006.md @@ -0,0 +1,227 @@ +# ADR-0006: Quarantine Synthetic Port Identity Intelligence + +**Date**: 2026-08-24 +**Status**: `PROPOSED` +**Governs**: `knowledge/ports/*/identity.json` and its consumers +**Evidence**: `docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md` + +--- + +## Context + +Every `identity.json` under `knowledge/ports/` was written by one of two bulk +generators, `tools/mass_populate_knowledge.py` (101 ports) and +`tools/populate_classes_and_ports.py` (18 ports). Each generator hardcodes a +template. Across the full corpus of 119 ports, `timezone` is `"UTC"` 119 times, +`walking_time_min` is `10` 119 times, `card_acceptance_pct` is `98` 119 times, +and every port carries an identical source record: + +```json +{"field": "all", "source_id": "src:official-port-authority", + "trust_level": "OFFICIAL", "retrieved_at": "2026-08-16T12:00:00Z"} +``` + +The audit establishes this from generator source, not from inference. These are +**synthetic/template-derived values without field-level evidence**. + +### Why the corpus-wide view was necessary + +Each file is individually well-formed and individually plausible. Barcelona +reads like researched data. The defect exists only in the distribution: one +distinct value across 119 globally distributed ports is not an observation, it +is a constant. No per-file review — however careful, and however many files it +covered — could have surfaced this, because the property that reveals the +defect is not a property of any file. + +This is the governing lesson. A machine-readable corpus is audited by scanning +it, not by sampling it. + +### Why port-by-port cleanup would have been epistemically misleading + +The originally commissioned work was a reconciliation sprint: triage each +port's fields, downgrade unsupported precision, reconcile against external +research. Applied here, that produces a large diff in which each hunk appears +to record a considered judgement about a specific port's specific claim. + +No such judgements would exist. There is one fact — *these are template +constants* — restated 119 times. A reviewer reading that diff would reasonably +conclude that 119 independent assessments had been made, and would be wrong. +The diff would misrepresent the epistemic work behind it, which is a worse +failure than the data defect it purports to fix: it would launder a mechanical +deletion as evidence work. + +**A single mechanical operation with one recorded rationale is more honest than +119 apparent judgements.** + +--- + +## Decision + +### D1 — The template-derived identity layer is not canonical port knowledge + +`knowledge/ports/*/identity.json` does not constitute evidence for any +passenger-facing fact. Its synthetic fields are quarantined: set to the +fail-closed state, not deleted, so that the retraction is visible in the data +and not merely in this document. + +### D2 — `field: "all"` cannot establish provenance + +A source record claiming to cover every field attests no field in particular. +Provenance is a claim that a specific document supports a specific assertion; +a claim covering everything makes no such connection and is therefore +unverifiable and unfalsifiable. + +`field: "all"` is prohibited on the port identity path. If a genuine case ever +arises — a single authoritative document that really does attest every field +in a record — it requires an explicit, named schema exception, not a blanket +allowance. + +### D3 — `OFFICIAL` describes evidence authority, never generator output + +`trust_level` is a property of the *evidence*: which body published it, in what +document, retrievable at what address. It is not a property of the code path +that wrote the field. A generator cannot confer `OFFICIAL` on values it +invented, and `src:official-port-authority` — a category noun formatted to +resemble a source identifier, resolving to no artifact — cannot serve as +evidence for anything. + +### D4 — UNKNOWN is publishable; synthetic precision is not + +A null `walking_time_min` tells a passenger to check. A synthetic `10` tells +them something false with the full authority of the system. The second is +strictly worse, and the difference is not marginal: unknown values invite +verification, whereas confident wrong values suppress it. + +Absence of evidence is a publishable state. Invented precision is not. + +### D5 — Passenger-critical facts fail closed + +Where a fact could mislead a traveller into a decision with real consequence — +missing a departure, calling a wrong emergency number, arriving at an +inaccessible gangway — insufficient support means the field is nulled, not +estimated, not defaulted, not carried over. + +This decision extends the quarantine to **`logistics.emergency_phone`**, which +was not in the original scope. The generators derive it from a country +allow-list with an else-branch, producing `112` for Mexico, Barbados, the +Cayman Islands and Israel — all incorrect. A wrong emergency number published +under `OFFICIAL` is the most directly harmful fact in the corpus, and D5 +admits no exception for it. + +`logistics.currency` is quarantined on the same basis: 31 ports carry the +literal string `"Local"`, an else-branch artefact rather than a value. + +### D6 — Consumers absorb UNKNOWN; they do not restore values + +Where a downstream consumer breaks because a field became null, the consumer +is fixed to handle the null. Restoring a synthetic value to keep a consumer +working reintroduces the defect and converts a knowledge-layer problem into a +permanent one. + +--- + +## Quarantine boundary + +### Quarantined — removed from canonical trust + +| Field | Action | Basis | +|---|---|---| +| `timezone` | → `null` | Template constant `"UTC"` × 119; all-aboard-critical | +| `terminals[].walking_time_min` | → `null` | Template constant `10` × 119 | +| `terminals[].distance_to_city_center_m` | → `null` | Template constants `500`/`800` | +| `terminals[].gangway_deck_default` | → `null` | Template constants `5`/`2` | +| `terminals[].step_free_access` | → `null` | Template constant `true` × 119; accessibility claim | +| `terminals[].berths` | → `[]` | Synthetic names interpolated from slug | +| `logistics.card_acceptance_pct` | → `null` | Template constant `98` × 119 | +| `logistics.currency` | → `null` | Generator lookup; 31 ports hold `"Local"` | +| `logistics.emergency_phone` | → `null` | Generator else-branch; confirmed wrong values (D5) | +| `negative_intelligence` | → `[]` | Two templates with port name interpolated | +| `sources[]` where `field == "all"` and `source_id == "src:official-port-authority"` | removed | D2, D3 | + +Scalars become `null` and lists become `[]` rather than being deleted. The key +remains present, so the data itself records that a claim was asserted and +withdrawn. A deleted key is indistinguishable from a claim never made. + +### Preserved — but explicitly NOT promoted + +`slug`, `name`, `un_locode`, `country`, `region`, `coordinates`, +`terminals[].name`. + +These are retained as **candidate identity data** for referential integrity; +consumers resolve ports by slug and the graph would lose 119 nodes without +them. Retention is a compatibility measure and confers no trust: + +- They are **not** validated. All 119 LOCODEs are syntactically well-formed and + none has been checked against the UNECE list. +- `USPEF` (`fort-lauderdale`, `port-everglades`) and `ITTRS` (`trieste`, + `venice-trieste`) each appear twice, indicating unresolved entity identity. +- Coordinates are generator-supplied and unverified. +- **No provenance is invented for them.** They carry no source record, which + correctly reflects that no evidence has been produced. Fabricating a + plausible source to fill the gap would repeat the defect this ADR exists to + correct. + +Validation is separate work requiring a real UNECE artifact. + +### Explicitly excluded from this decision + +**Barcelona, Genoa, Marseille, Messina, Naples, Valletta** hold a richer +eight-file layout (`port.json`, `transport.json`, `medical.json`, +`emergency.json`, `terminals.json`, `sustainability.json`, `weather.json`). + +Their provenance model is separately inadequate: `source_artifact: +"CRUISE_PORT_INTELLIGENCE_PROFILE_WEST_MED_2026"` is a name rather than a +content address, and per-item `provenance` strings such as `"BCN-PA-TERM-A"` +resolve to nothing. + +But their **content shows no template fingerprints**. Values vary per port and +are specific and checkable — named hospitals with addresses and telephone +numbers, named metro lines, named terminal operators. This content **must not +be assumed invalid merely because `identity.json` in the same directory is +synthetic.** It requires its own audit, which this ADR does not perform and +does not prejudge. Only their `identity.json` files are quarantined here, on +identical mechanical grounds to the other 113. + +--- + +## Enforcement + +`tests/test_port_identity_quarantine.py` asserts thirteen corpus-wide +invariants. They are **distribution-based, not per-file**, for the reason given +above: a per-file assertion cannot distinguish a researched `10` from a +template `10`, whereas a cardinality check across 119 ports can. + +The core rule: *a passenger-facing value may not take one identical value +across the entire corpus unless a field-scoped source attests it.* Values +carrying real field-scoped provenance are exempt, so the tests constrain +unsourced data without obstructing sourced data. + +Documentation alone would not hold. The generators remain in `tools/` and +would restore every quarantined value if re-run. The tests are the structural +guard, and they fail closed. + +--- + +## Consequences + +**Accepted:** the port knowledge base becomes visibly sparse. 119 ports lose +most passenger-facing fields and gain no replacements. This is the correct +state — it is what the evidence supports — and it makes the real coverage +legible for the first time. + +**Not addressed:** `tools/generate_frontend_bridge.py` hardcodes the same +synthetic values independently of the knowledge layer, so +`frontend/src/generated/ports.ts` will continue publishing them after this +change. It additionally emits `officialSource.url: "https://www.timonelo.com"` +under `trustLevel: "OFFICIAL"`, and silently defaults a missing LOCODE to +Genoa's `ITGOA`. Fixing this is a frontend contract change — the `PortData` +interface declares these fields non-optional — and requires a decision about +rendering UNKNOWN. See audit §7 U-1. **Until it is fixed, the passenger-facing +surface remains contaminated.** + +**Not addressed:** `data/` generated artifacts are already stale on `develop` +independently of this change (audit §7 U-2), so they are excluded here. + +**Follow-on work:** UNECE LOCODE validation; entity-identity ADR for the two +duplicate pairs; provenance audit of the six rich-layout ports; frontend bridge +remediation; retirement or gating of the two generators. diff --git a/frontend/src/components/PortExplorer.trust.test.tsx b/frontend/src/components/PortExplorer.trust.test.tsx new file mode 100644 index 0000000..b21bd3a --- /dev/null +++ b/frontend/src/components/PortExplorer.trust.test.tsx @@ -0,0 +1,196 @@ +import { describe, it, expect } from 'vitest'; +import { renderToStaticMarkup } from 'react-dom/server'; +import { PortExplorer } from './PortExplorer'; +import { LanguageProvider } from '../i18n'; +import { PORTS_REGISTRY, getPortBySlug } from '../ports'; +import { PORTS_REGISTRY as RAW_PORTS } from '../generated/ports'; + +/** + * Passenger-surface trust boundary (audit U-1). + * + * The port page is where an evidence gap becomes a decision. Someone reads a + * walking time and leaves the ship without a shuttle; reads an emergency + * number and dials it. So the rule for this surface is stricter than "do not + * display wrong data": it must not convert an absent value into advice. + * + * The specific defect these cover: `(walkingTimeMin ?? 0) > 0` collapsed + * "unknown" and "zero" into one branch and answered both with "Shuttle + * transfer or taxi recommended". Not knowing how far the centre is does not + * imply a shuttle exists, and it does not imply walking is impractical. + * + * Assertions run against real rendered markup rather than against the model, + * because the claim under test is what a passenger sees. + */ + +const render = (slug: string) => + renderToStaticMarkup( + + {}} /> + , + ); + +const ALL_SLUGS = PORTS_REGISTRY.map((p) => p.slug); + +/** Advice that must never appear as a consequence of a missing value. */ +const OPERATIONAL_ADVICE = [ + 'Shuttle transfer or taxi recommended', + 'Shuttle-Transfer oder Taxi empfohlen', + 'shuttle recommended', + 'taxi recommended', + 'Taxi empfohlen', + 'walking not recommended', + 'Gehen nicht empfohlen', +]; + +describe('PortExplorer — unknown values stay unknown', () => { + it('never renders transport advice for any port', () => { + for (const slug of ALL_SLUGS) { + const html = render(slug); + for (const phrase of OPERATIONAL_ADVICE) { + expect( + html.toLowerCase(), + `port "${slug}" renders operational advice: ${phrase}`, + ).not.toContain(phrase.toLowerCase()); + } + } + }); + + it('states walking time as unknown rather than inferring a transfer', () => { + for (const slug of ALL_SLUGS) { + const port = getPortBySlug(slug); + if (port?.distanceToCenterKm == null) continue; // panel not rendered + const html = render(slug); + const known = + typeof port.walkingTimeMin === 'number' && port.walkingTimeMin > 0; + if (!known) { + expect( + html.includes('Walking time unknown') || + html.includes('Gehzeit unbekannt'), + `port "${slug}" has no walking time but does not say so`, + ).toBe(true); + } + } + }); + + it('renders a known positive walking time verbatim', () => { + // Guards against fixing the leak by suppressing real values too. + const withWalk = PORTS_REGISTRY.find( + (p) => + typeof p.walkingTimeMin === 'number' && + p.walkingTimeMin > 0 && + p.distanceToCenterKm != null, + ); + if (!withWalk) { + // Correct current state: every curated walking time was unsourced and + // has been failed closed. Nothing to assert until one is sourced. + expect( + PORTS_REGISTRY.every((p) => p.walkingTimeMin == null), + ).toBe(true); + return; + } + const html = render(withWalk.slug); + expect(html).toContain(String(withWalk.walkingTimeMin)); + }); + + it('treats walkingTimeMin === 0 as unknown, not as "too far to walk"', () => { + // 0 was an undocumented sentinel. Nothing may read meaning into it. + const zeroed = PORTS_REGISTRY.filter((p) => p.walkingTimeMin === 0); + for (const port of zeroed) { + const html = render(port.slug); + expect( + html.includes('Walking time unknown') || + html.includes('Gehzeit unbekannt'), + ).toBe(true); + } + }); +}); + +describe('PortExplorer — earlier U-1 fixes stay fixed', () => { + it('never renders a slug-derived UN/LOCODE', () => { + for (const slug of ALL_SLUGS) { + const html = render(slug); + expect( + html, + `port "${slug}" renders its slug as a UN/LOCODE`, + ).not.toContain(`UN/LOCODE: ${slug.toUpperCase()}`); + } + }); + + it('never claims step-free access', () => { + for (const slug of ALL_SLUGS) { + const html = render(slug); + expect(html).not.toContain('step-free'); + expect(html).not.toContain('stufenlos'); + } + }); + + it('never cites Timonelo as an official source', () => { + for (const slug of ALL_SLUGS) { + expect(render(slug)).not.toContain('timonelo.com'); + } + }); +}); + +describe('CURATED_PORT_STORIES cannot inject unsourced operational facts', () => { + const OPERATIONAL_FIELDS = [ + 'walkingTimeMin', + 'distanceToCenterKm', + 'gangwayDeck', + 'terminalPier', + 'emergencyPhone', + 'policePhone', + 'transitNoteDe', + 'transitNoteEn', + 'airportTransitDe', + 'airportTransitEn', + 'stepFreeAccess', + ] as const; + + it.each(OPERATIONAL_FIELDS)( + '%s is null for every port until sourced upstream', + (field) => { + for (const port of PORTS_REGISTRY) { + expect( + port[field], + `port "${port.slug}" carries an unsourced ${field}`, + ).toBeNull(); + } + }, + ); + + it('does not override a null upstream value with a curated one', () => { + // The shim may narrow an upstream value to null; it may never widen null + // into a value. Checked against the generated bridge output directly. + for (const port of PORTS_REGISTRY) { + const raw = RAW_PORTS.find((r) => r.slug === port.slug); + if (!raw) continue; + if (raw.walkingTimeMin == null) expect(port.walkingTimeMin).toBeNull(); + if (raw.gangwayDeckDefault == null) expect(port.gangwayDeck).toBeNull(); + if (raw.stepFreeAccess == null) expect(port.stepFreeAccess).toBeNull(); + if (raw.emergencyPhone == null) expect(port.emergencyPhone).toBeNull(); + } + }); + + it('emits no bullet list of unsourced port essentials', () => { + for (const port of PORTS_REGISTRY) { + expect(port.timEssentialsDe).toHaveLength(0); + expect(port.timEssentialsEn).toHaveLength(0); + } + }); + + it('keeps descriptive editorial copy', () => { + // Fail-closed applies to operational facts, not to framing. Deleting the + // narrative would be over-correction, and the page still needs to read. + for (const port of PORTS_REGISTRY) { + expect(port.shortName.length).toBeGreaterThan(0); + expect(port.headlineEn.length).toBeGreaterThan(0); + expect(port.storyEn.length).toBeGreaterThan(0); + } + }); +}); + +describe('getPortBySlug', () => { + it('returns undefined for an unknown slug rather than another port', () => { + expect(getPortBySlug('not-a-real-port')).toBeUndefined(); + }); +}); diff --git a/frontend/src/components/PortExplorer.tsx b/frontend/src/components/PortExplorer.tsx index 7899925..3a8798d 100644 --- a/frontend/src/components/PortExplorer.tsx +++ b/frontend/src/components/PortExplorer.tsx @@ -55,7 +55,9 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp > {port.shortName} - ({port.unLocode}) + {port.unLocode && ( + ({port.unLocode}) + )} ))} @@ -68,7 +70,10 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp {isGerman ? 'Heute auf der Brücke wichtig' : "Today's Bridge Essentials"} · - {selectedPort.shortName} ({selectedPort.unLocode}) + + {selectedPort.shortName} + {selectedPort.unLocode ? ` (${selectedPort.unLocode})` : ''} +
@@ -96,8 +101,8 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp
- UN/LOCODE: {selectedPort.unLocode} - {selectedPort.country} + UN/LOCODE: {selectedPort.unLocode ?? (isGerman ? 'unbekannt' : 'unknown')} + {selectedPort.country ?? (isGerman ? 'unbekannt' : 'unknown')}
@@ -120,7 +125,9 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp

{isGerman ? `Deck ${selectedPort.gangwayDeck} regulär` : `Deck ${selectedPort.gangwayDeck} (Regular)`}

-

{selectedPort.terminalPier}

+ {selectedPort.terminalPier && ( +

{selectedPort.terminalPier}

+ )} )} @@ -133,10 +140,24 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp

{selectedPort.distanceToCenterKm} km

+ {/* + Three states, not two. `?? 0` previously collapsed null + into the same branch as 0 and answered both with + "Shuttle transfer or taxi recommended" -- turning "we do + not know how long the walk is" into operational advice. + An unknown walking time does not imply that walking is + impractical, that a shuttle exists, or that a taxi is + warranted. + + 0 is treated as unknown as well: it appears in the data + as an informal sentinel for "too far to walk", but that + meaning is documented nowhere and is indistinguishable + here from a missing value. + */}

- {(selectedPort.walkingTimeMin ?? 0) > 0 - ? (isGerman ? `ca. ${selectedPort.walkingTimeMin} Min. Gehzeit (stufenlos)` : `approx. ${selectedPort.walkingTimeMin} min walk (step-free)`) - : (isGerman ? 'Shuttle-Transfer oder Taxi empfohlen' : 'Shuttle transfer or taxi recommended')} + {typeof selectedPort.walkingTimeMin === 'number' && selectedPort.walkingTimeMin > 0 + ? (isGerman ? `ca. ${selectedPort.walkingTimeMin} Min. Gehzeit` : `approx. ${selectedPort.walkingTimeMin} min walk`) + : (isGerman ? 'Gehzeit unbekannt' : 'Walking time unknown')}

)} @@ -148,25 +169,40 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp

{t.ports.localTransit}

-
- -
- - {isGerman ? 'Öffentlicher Nahverkehr & Fußweg' : 'Local Transit & Walking Path'} - -

{transit}

+ {transit && ( +
+ +
+ + {isGerman ? 'Öffentlicher Nahverkehr & Fußweg' : 'Local Transit & Walking Path'} + +

{transit}

+
-
+ )} -
- -
- - {isGerman ? 'Flughafen-Transfer' : 'Airport Connection'} - -

{airport}

+ {airport && ( +
+ +
+ + {isGerman ? 'Flughafen-Transfer' : 'Airport Connection'} + +

{airport}

+
-
+ )} + + {/* No transit guidance without evidence. The heading promises + a recommendation, so say plainly that there isn't one + rather than leaving an empty panel that reads as a bug. */} + {!transit && !airport && ( +

+ {isGerman + ? 'Keine gesicherten Transferinformationen für diesen Hafen hinterlegt.' + : 'No verified transit information on file for this port.'} +

+ )}
@@ -207,8 +243,19 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp : 'Local port authority dispatch and emergency channels:'}

-

{isGerman ? 'Hafen / Polizei:' : 'Port / Police:'} {selectedPort.policePhone}

-

{isGerman ? 'Notarzt & Rettung:' : 'Medical & Emergency:'} {selectedPort.emergencyPhone}

+ {selectedPort.policePhone && ( +

{isGerman ? 'Hafen / Polizei:' : 'Port / Police:'} {selectedPort.policePhone}

+ )} + {selectedPort.emergencyPhone && ( +

{isGerman ? 'Notarzt & Rettung:' : 'Medical & Emergency:'} {selectedPort.emergencyPhone}

+ )} + {!selectedPort.policePhone && !selectedPort.emergencyPhone && ( +

+ {isGerman + ? 'Keine gesicherten Notrufnummern hinterlegt.' + : 'No verified emergency numbers on file.'} +

+ )}
diff --git a/frontend/src/components/UniversalSearchModal.tsx b/frontend/src/components/UniversalSearchModal.tsx index f912496..ab7f053 100644 --- a/frontend/src/components/UniversalSearchModal.tsx +++ b/frontend/src/components/UniversalSearchModal.tsx @@ -65,7 +65,9 @@ export function UniversalSearchModal({ // 2. Ports PORTS_REGISTRY.forEach((p) => { - if (p.name.toLowerCase().includes(q) || p.slug.includes(q) || p.unLocode.toLowerCase().includes(q) || p.country.toLowerCase().includes(q)) { + // Optional-chained: a port with no sourced LOCODE or country is still + // searchable by name and slug, and simply does not match on those fields. + if (p.name.toLowerCase().includes(q) || p.slug.includes(q) || p.unLocode?.toLowerCase().includes(q) || p.country?.toLowerCase().includes(q)) { results.push({ id: `port:${p.slug}`, type: 'port', diff --git a/frontend/src/generated/ports.ts b/frontend/src/generated/ports.ts index 6ee862c..4ea5671 100644 --- a/frontend/src/generated/ports.ts +++ b/frontend/src/generated/ports.ts @@ -1,5392 +1,2300 @@ // AUTO-GENERATED BY tools/generate_frontend_bridge.py // DO NOT EDIT MANUALLY. SOURCE: data/cruise_intelligence_db.json +// Nullable by design. `null` means the knowledge layer holds no evidence for +// this field; it must render as unavailable, never as a substituted default. export interface PortData { slug: string; - name: string; - unLocode: string; - country: string; - region: string; - headline: string; - terminalName: string; + name: string | null; + unLocode: string | null; + country: string | null; + region: string | null; + terminalName: string | null; berths: string[]; - gangwayDeckDefault: number; - distanceToCenterM: number; - walkingTimeMin: number; - stepFreeAccess: boolean; - transitNote: string; - airportTransit: string; - currency: string; - cardAcceptancePct: number; - emergencyPhone: string; + gangwayDeckDefault: number | null; + distanceToCenterM: number | null; + walkingTimeMin: number | null; + stepFreeAccess: boolean | null; + currency: string | null; + cardAcceptancePct: number | null; + emergencyPhone: string | null; negativeIntelligence: string[]; officialSource: { - authority: string; - url: string; - trustLevel: 'OFFICIAL' | 'VERIFIED'; - }; + authority: string | null; + url: string | null; + sourceId: string; + field: string; + trustLevel: string | null; + } | null; callingShips: { slug: string; name: string }[]; } export const PORTS_REGISTRY: PortData[] = [ { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "France", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Ajaccio (Corsica)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ajaccio (Corsica) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "ajaccio", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FRAJA", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port Everglades", + "negativeIntelligence": [], + "officialSource": null, + "region": "Florida / Caribbean", + "slug": "fort-lauderdale", + "stepFreeAccess": null, + "terminalName": "Terminals 2, 4, 18, 19, 21, 25, 26, 29", + "unLocode": "USPEF", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Iceland", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Atlantic / Iceland.", - "name": "Port of Akureyri", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Akureyri Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Atlantic / Iceland", - "slug": "akureyri", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ISAKU", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Barbados", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Bridgetown (Barbados)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Southern Caribbean", + "slug": "bridgetown", + "stepFreeAccess": null, + "terminalName": "Bridgetown Cruise Terminal (Deep Water Harbour)", + "unLocode": "BBBGI", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Norwegian Fjords.", - "name": "Port of Ålesund", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ålesund Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Norwegian Fjords", - "slug": "alesund", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NOAES", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Turkey", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Kusadasi (Ephesus Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Aegean / Turkey", + "slug": "kusadasi", + "stepFreeAccess": null, + "terminalName": "Ege Port Kusadasi (Direct Bazaar Promenade)", + "unLocode": "TRKUS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Netherlands", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Passenger Terminal Amsterdam (PTA)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Passenger Terminal Amsterdam (PTA) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "amsterdam", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NLAMS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Mexico", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ensenada (Baja California)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Mexican Riviera", + "slug": "ensenada", + "stepFreeAccess": null, + "terminalName": "Muelle de Cruceros Ensenada", + "unLocode": "MXESE", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Estonia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Tallinn", + "negativeIntelligence": [], + "officialSource": null, + "region": "Baltic Sea", + "slug": "tallinn", + "stepFreeAccess": null, + "terminalName": "Old City Harbour Cruise Promenade", + "unLocode": "EETLL", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Trieste (Molo Bersaglieri)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "trieste", + "stepFreeAccess": null, + "terminalName": "Stazione Marittima di Trieste", + "unLocode": "ITTRS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Canary Islands.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Arrecife (Lanzarote)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Arrecife (Lanzarote) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Canary Islands", "slug": "arrecife", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Muelle de Los Mármoles & Muelle de Cruceros", "unLocode": "ESACE", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Barcelona", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Barcelona Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Naples (Napoli)", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "barcelona", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESBCN", - "walkingTimeMin": 10 + "slug": "naples", + "stepFreeAccess": null, + "terminalName": "Stazione Marittima di Napoli (Molo Angioino)", + "unLocode": "ITNAP", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Bari", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Bari Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "bari", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITBRI", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Switzerland", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Rhine River.", - "name": "Port of Basel (Rhine Hub)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Basel (Rhine Hub) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Rhine River", - "slug": "basel", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "CHBSL", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Civitavecchia (Rome)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "civitavecchia", + "stepFreeAccess": null, + "terminalName": "Amerigo Vespucci Cruise Terminal (Quay 12/25)", + "unLocode": "ITCVV", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for East Coast / New York Harbour.", - "name": "Cape Liberty Cruise Port (Bayonne)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Cape Liberty Cruise Port (Bayonne) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "East Coast / New York Harbour", - "slug": "bayonne-cape-liberty", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USBYN", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Portugal", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Lisbon (Porto de Lisboa)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Atlantic / Western Europe", + "slug": "lisbon", + "stepFreeAccess": null, + "terminalName": "Santa Apolónia / Jardim do Tabaco Terminal", + "unLocode": "PTLIS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Norwegian Fjords.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Bergen", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Bergen Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Norwegian Fjords", "slug": "bergen", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Skolten, Bontelabo & Jekteviksbukten", "unLocode": "NOBGO", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for New England.", - "name": "Port of Boston (Flynn Cruiseport)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Boston (Flynn Cruiseport) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "New England", - "slug": "boston", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USBOS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "St. Lucia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Castries (St. Lucia)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Southern Caribbean", + "slug": "castries", + "stepFreeAccess": null, + "terminalName": "Pointe Seraphine & La Place Carenage", + "unLocode": "LCCAS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Slovakia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Danube River.", - "name": "Port of Bratislava (Danube)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Bratislava (Danube) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Danube River", - "slug": "bratislava", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "SKBTS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United Kingdom", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Dover", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "dover", + "stepFreeAccess": null, + "terminalName": "Dover Western Docks Terminals 1 & 2", + "unLocode": "GBDOV", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Columbus Cruise Center Bremerhaven (CCCB)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Columbus Cruise Center Bremerhaven (CCCB) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "bremerhaven", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DEBRV", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Mexico", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Cozumel", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Caribbean", + "slug": "cozumel", + "stepFreeAccess": null, + "terminalName": "Punta Langosta, International Pier, Puerta Maya", + "unLocode": "MXCZM", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Barbados", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Southern Caribbean.", - "name": "Port of Bridgetown (Barbados)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Bridgetown (Barbados) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Southern Caribbean", - "slug": "bridgetown", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "BBBGI", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ravenna (Venice Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "venice-ravenna", + "stepFreeAccess": null, + "terminalName": "Porto Corsini Terminal Crociere", + "unLocode": "ITRAN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Hungary", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Danube River.", - "name": "Port of Budapest (Danube River)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Budapest (Danube River) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Danube River", - "slug": "budapest", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "HUBUD", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of New Orleans", + "negativeIntelligence": [], + "officialSource": null, + "region": "Gulf Coast / Mississippi", + "slug": "new-orleans", + "stepFreeAccess": null, + "terminalName": "Erato Street & Julia Street Cruise Terminals", + "unLocode": "USMSY", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Argentina", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for South America.", - "name": "Port of Buenos Aires (Benito Quinquela Martín)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Buenos Aires (Benito Quinquela Martín) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "South America", - "slug": "buenos-aires", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ARBUE", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Norway", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Honningsvåg (North Cape)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Arctic Norway", + "slug": "honDefault-nordkapp", + "stepFreeAccess": null, + "terminalName": "Honningsvåg Pier (Bus to North Cape Hall)", + "unLocode": "NOHVG", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Mexico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Mexican Riviera.", - "name": "Port of Cabo San Lucas (Baja California)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Cabo San Lucas (Baja California) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Mexican Riviera", - "slug": "cabo-san-lucas", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MXCSL", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Croatia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Split", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "split", + "stepFreeAccess": null, + "terminalName": "Gat Sv. Duje & Gat Sv. Petra (Diocletian Palace Gate)", + "unLocode": "HRSPU", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Atlantic / Andalusia.", - "name": "Port of Cadiz", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Cadiz Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Atlantic / Andalusia", - "slug": "cadiz", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESCAD", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Iceland", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Akureyri", + "negativeIntelligence": [], + "officialSource": null, + "region": "Atlantic / Iceland", + "slug": "akureyri", + "stepFreeAccess": null, + "terminalName": "Oddeyrarbryggja & Tangabryggja", + "unLocode": "ISAKU", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Cagliari (Sardinia)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Cagliari (Sardinia) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Bari", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "bari", + "stepFreeAccess": null, + "terminalName": "Banchina di Ponente & Molo San Vito", + "unLocode": "ITBRI", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "France", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Villefranche-sur-Mer / Nice", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "cagliari", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITCAG", - "walkingTimeMin": 10 + "slug": "nice-villefranche", + "stepFreeAccess": null, + "terminalName": "Rade de Villefranche Tender Anchorage", + "unLocode": "FRVFR", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "France", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Cannes", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Cannes Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Marseille Fos", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "cannes", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FRCEQ", - "walkingTimeMin": 10 + "slug": "marseille", + "stepFreeAccess": null, + "terminalName": "Marseille Provence Cruise Terminal (Môle Léon Gourret)", + "unLocode": "FRMRS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "St. Lucia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Southern Caribbean.", - "name": "Port of Castries (St. Lucia)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Castries (St. Lucia) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Southern Caribbean", - "slug": "castries", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "LCCAS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United Kingdom", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "London Tilbury / Greenwich Cruise Terminal", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "london", + "stepFreeAccess": null, + "terminalName": "London International Cruise Terminal Tilbury", + "unLocode": "GBLON", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Civitavecchia (Rome)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Civitavecchia (Rome) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of La Spezia (Cinque Terre Gateway)", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "civitavecchia", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITCVV", - "walkingTimeMin": 10 + "slug": "la-spezia", + "stepFreeAccess": null, + "terminalName": "Molo Garibaldi Cruise Terminal", + "unLocode": "ITSPE", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Rhine River.", - "name": "Port of Cologne (Köln / Rhine)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Cologne (Köln / Rhine) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Rhine River", - "slug": "cologne", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DECGN", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Aruba", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Oranjestad (Aruba)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Southern Caribbean", + "slug": "oranjestad", + "stepFreeAccess": null, + "terminalName": "Aruba Ports Authority Cruise Terminal", + "unLocode": "AWORJ", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Denmark", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", - "name": "Port of Copenhagen", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Copenhagen Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Baltic Sea", - "slug": "copenhagen", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DKCPH", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Jamaica", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ocho Rios (Jamaica)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Caribbean", + "slug": "ocho-rios", + "stepFreeAccess": null, + "terminalName": "Turtle Beach & James Bond Pier", + "unLocode": "JMOCH", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Greece", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Ionian Sea.", - "name": "Port of Corfu (Kerkyra)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Corfu (Kerkyra) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Ionian Sea", - "slug": "corfu", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GRCFU", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Rhodes", + "negativeIntelligence": [], + "officialSource": null, + "region": "Aegean Sea", + "slug": "rhodes", + "stepFreeAccess": null, + "terminalName": "Rhodes Acandia & Tourist Port (Medieval Walls)", + "unLocode": "GRRHO", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Mexico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Caribbean.", - "name": "Port of Costa Maya (Mahahual)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Costa Maya (Mahahual) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Caribbean", - "slug": "costa-maya", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MXCMY", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Spain", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ibiza", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "ibiza", + "stepFreeAccess": null, + "terminalName": "Dique del Botafoc", + "unLocode": "ESIBZ", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Mexico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Caribbean.", - "name": "Port of Cozumel", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Cozumel Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Caribbean", - "slug": "cozumel", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MXCZM", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Portugal", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Pinhão River Pier (Douro Valley)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Douro River", + "slug": "pinhao", + "stepFreeAccess": null, + "terminalName": "Pinhão Pier (Vintage Port Quinta Heart)", + "unLocode": "PTPNH", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United Kingdom", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Port of Dover", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Dover Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "dover", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GBDOV", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Croatia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Dubrovnik (Gruž)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Dubrovnik (Gruž) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "dubrovnik", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "HRDBV", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Mexico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Mexican Riviera.", - "name": "Port of Ensenada (Baja California)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ensenada (Baja California) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Mexican Riviera", - "slug": "ensenada", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MXESE", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Norwegian Fjords.", - "name": "Port of Flåm (Aurlandsfjord)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Flåm (Aurlandsfjord) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Norwegian Fjords", - "slug": "flam", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NOFLA", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Florida / Caribbean.", - "name": "Port Everglades", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port Everglades Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Florida / Caribbean", - "slug": "fort-lauderdale", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USPEF", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Portugal", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Atlantic / Madeira.", - "name": "Port of Funchal (Madeira)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Funchal (Madeira) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Atlantic / Madeira", - "slug": "funchal", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "PTFNC", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Texas / Gulf Coast.", - "name": "Port of Galveston", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Galveston Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Texas / Gulf Coast", - "slug": "galveston", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USGLS", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Norwegian Fjords.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Geiranger (Geirangerfjord)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Geiranger (Geirangerfjord) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Norwegian Fjords", "slug": "geiranger", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Geiranger SeaWalk Floating Pier & Tender", "unLocode": "NOGEI", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Genoa (Genova)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Genoa (Genova) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "genoa", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITGOA", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Messina (Sicily)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Central Mediterranean", + "slug": "messina", + "stepFreeAccess": null, + "terminalName": "Banchina Colapesce & Molo Marconi", + "unLocode": "ITMSN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Cayman Islands", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Caribbean.", - "name": "Port of Grand Cayman (George Town)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Grand Cayman (George Town) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Caribbean", - "slug": "grand-cayman", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "KYGEC", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Portugal", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Porto / Douro River", + "negativeIntelligence": [], + "officialSource": null, + "region": "Douro River", + "slug": "porto", + "stepFreeAccess": null, + "terminalName": "Cais da Ribeira & Vila Nova de Gaia", + "unLocode": "PTOPO", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Israel", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Eastern Mediterranean.", - "name": "Port of Haifa", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Haifa Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Eastern Mediterranean", - "slug": "haifa", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ILHFA", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Netherlands", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Passenger Terminal Amsterdam (PTA)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "amsterdam", + "stepFreeAccess": null, + "terminalName": "Passenger Terminal Amsterdam (Piet Heinkade)", + "unLocode": "NLAMS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Port of Hamburg", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Hamburg Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "hamburg", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DEHAM", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Passau (Three Rivers City / Danube)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Danube River", + "slug": "passau", + "stepFreeAccess": null, + "terminalName": "Passau Lindau & Racklau Danube Berths", + "unLocode": "DEPAS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Finland", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", - "name": "Port of Helsinki", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Helsinki Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Baltic Sea", - "slug": "helsinki", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FIHEL", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Norway", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Tromsø (Arctic Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Arctic Norway", + "slug": "tromso", + "stepFreeAccess": null, + "terminalName": "Breivika Cruise Port & Prostneset", + "unLocode": "NOTOS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Greece", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Eastern Mediterranean.", - "name": "Port of Heraklion (Crete)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Heraklion (Crete) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Eastern Mediterranean", - "slug": "heraklion", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GRHER", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Norway", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ålesund", + "negativeIntelligence": [], + "officialSource": null, + "region": "Norwegian Fjords", + "slug": "alesund", + "stepFreeAccess": null, + "terminalName": "Prestebrygga & Skansekai (Art Nouveau Center)", + "unLocode": "NOAES", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Arctic Norway.", - "name": "Port of Honningsvåg (North Cape)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Honningsvåg (North Cape) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Arctic Norway", - "slug": "honDefault-nordkapp", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NOHVG", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Sint Maarten", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of St. Maarten (Philipsburg)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Eastern Caribbean", + "slug": "st-maarten", + "stepFreeAccess": null, + "terminalName": "Dr. A.C. Wathey Cruise Facility", + "unLocode": "SXMMA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Hong Kong", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for East Asia.", - "name": "Kai Tak Cruise Terminal (Hong Kong)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Kai Tak Cruise Terminal (Hong Kong) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "East Asia", - "slug": "hong-kong", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "HKHKG", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Los Angeles (World Cruise Center)", + "negativeIntelligence": [], + "officialSource": null, + "region": "US West Coast", + "slug": "los-angeles", + "stepFreeAccess": null, + "terminalName": "Berths 91-93 San Pedro", + "unLocode": "USLAX", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Ibiza", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ibiza Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Valencia", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "ibiza", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESIBZ", - "walkingTimeMin": 10 + "slug": "valencia", + "stepFreeAccess": null, + "terminalName": "Muelle Transversales & Poniente", + "unLocode": "ESVLC", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Turkey", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Bosphorus / Black Sea.", - "name": "Galataport Istanbul", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Galataport Istanbul Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Bosphorus / Black Sea", - "slug": "istanbul", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "TRIST", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Cyprus", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Limassol", + "negativeIntelligence": [], + "officialSource": null, + "region": "Eastern Mediterranean", + "slug": "limassol", + "stepFreeAccess": null, + "terminalName": "DP World Limassol Cruise Terminal", + "unLocode": "CYLMS", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Trieste (Venice Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "venice-trieste", + "stepFreeAccess": null, + "terminalName": "Trieste Maritime Terminal (Molo Bersaglieri)", + "unLocode": "ITTRS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Alaska Inside Passage.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Juneau (Alaska)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Juneau (Alaska) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Alaska Inside Passage", "slug": "juneau", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Franklin Dock, Cruise Ship Terminal, AJ Dock", "unLocode": "USJNU", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Alaska Inside Passage.", - "name": "Port of Ketchikan (Alaska)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ketchikan (Alaska) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Alaska Inside Passage", - "slug": "ketchikan", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USKTN", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Germany", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Cologne (Köln / Rhine)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Rhine River", + "slug": "cologne", + "stepFreeAccess": null, + "terminalName": "Konrad-Adenauer-Ufer & Frankenwerft (Cathedral View)", + "unLocode": "DECGN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Kiel", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Kiel Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Baltic Sea", "slug": "kiel", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Ostseekai & Ostuferhafen", "unLocode": "DEKEL", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Rhine River.", - "name": "Koblenz (Deutsches Eck / Rhine & Moselle)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Koblenz (Deutsches Eck / Rhine & Moselle) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Rhine River", - "slug": "koblenz", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DEKOB", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Mexico", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Cabo San Lucas (Baja California)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Mexican Riviera", + "slug": "cabo-san-lucas", + "stepFreeAccess": null, + "terminalName": "Marina Cabo Tender Pier (Land's End Arch)", + "unLocode": "MXCSL", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Montenegro", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Kotor", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Kotor Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "kotor", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MEKOT", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Spain", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Cadiz", + "negativeIntelligence": [], + "officialSource": null, + "region": "Atlantic / Andalusia", + "slug": "cadiz", + "stepFreeAccess": null, + "terminalName": "Muelle Alfonso XIII (Direct Old Town Gate)", + "unLocode": "ESCAD", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Turkey", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Aegean / Turkey.", - "name": "Port of Kusadasi (Ephesus Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Kusadasi (Ephesus Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Aegean / Turkey", - "slug": "kusadasi", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "TRKUS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Malta", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Grand Harbour (Valletta, Malta)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Central Mediterranean", + "slug": "valletta", + "stepFreeAccess": null, + "terminalName": "Valletta Waterfront (Pinto Wharf)", + "unLocode": "MTMLA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of La Spezia (Cinque Terre Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of La Spezia (Cinque Terre Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "la-spezia", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITSPE", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Slovakia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Bratislava (Danube)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Danube River", + "slug": "bratislava", + "stepFreeAccess": null, + "terminalName": "Fajnorovo Nábrežie (Old Town Promenade)", + "unLocode": "SKBTS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Canary Islands.", - "name": "Port of Las Palmas (Gran Canaria)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Las Palmas (Gran Canaria) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Canary Islands", - "slug": "las-palmas", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESLPA", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Skagway (Alaska)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Alaska Inside Passage", + "slug": "skagway", + "stepFreeAccess": null, + "terminalName": "Ore Dock, Broadway Dock, Railroad Dock", + "unLocode": "USSGY", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "France", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Port of Le Havre (Paris Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Le Havre (Paris Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "le-havre", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FRLEH", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Norway", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Flåm (Aurlandsfjord)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Norwegian Fjords", + "slug": "flam", + "stepFreeAccess": null, + "terminalName": "Flåm Cruise Pier (Direct Flåmsbana Railway)", + "unLocode": "NOFLA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Cyprus", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Eastern Mediterranean.", - "name": "Port of Limassol", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Limassol Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Israel", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Haifa", + "negativeIntelligence": [], + "officialSource": null, "region": "Eastern Mediterranean", - "slug": "limassol", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "CYLMS", - "walkingTimeMin": 10 + "slug": "haifa", + "stepFreeAccess": null, + "terminalName": "Haifa Passenger Terminal", + "unLocode": "ILHFA", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Iceland", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Reykjavik", + "negativeIntelligence": [], + "officialSource": null, + "region": "Atlantic / Iceland", + "slug": "reykjavik", + "stepFreeAccess": null, + "terminalName": "Skarfabakki & Miðbakki Harbour", + "unLocode": "ISREY", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Portugal", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Atlantic / Western Europe.", - "name": "Port of Lisbon (Porto de Lisboa)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Lisbon (Porto de Lisboa) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Atlantic / Western Europe", - "slug": "lisbon", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "PTLIS", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Funchal (Madeira)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Atlantic / Madeira", + "slug": "funchal", + "stepFreeAccess": null, + "terminalName": "Cais Sul Cruise Terminal", + "unLocode": "PTFNC", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Livorno (Florence/Pisa Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Livorno (Florence/Pisa Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "livorno", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITLIV", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Puerto Rico", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of San Juan (Puerto Rico)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Eastern Caribbean", + "slug": "san-juan", + "stepFreeAccess": null, + "terminalName": "Old San Juan Piers 1-4 & Pan American Pier", + "unLocode": "PRSJU", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United Kingdom", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "London Tilbury / Greenwich Cruise Terminal", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "London Tilbury / Greenwich Cruise Terminal Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "london", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GBLON", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Montenegro", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Kotor", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "kotor", + "stepFreeAccess": null, + "terminalName": "Luka Kotor (Main Pier & Fjord Anchorage)", + "unLocode": "MEKOT", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for US West Coast.", - "name": "Port of Los Angeles (World Cruise Center)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Los Angeles (World Cruise Center) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "US West Coast", - "slug": "los-angeles", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USLAX", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Germany", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Koblenz (Deutsches Eck / Rhine & Moselle)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Rhine River", + "slug": "koblenz", + "stepFreeAccess": null, + "terminalName": "Konrad-Adenauer-Ufer Piers 1-9", + "unLocode": "DEKOB", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Malaga", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Malaga Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "malaga", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESAGP", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Bahamas", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Nassau Cruise Port (Bahamas)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Bahamas / Caribbean", + "slug": "nassau", + "stepFreeAccess": null, + "terminalName": "Prince George Wharf", + "unLocode": "BSNAS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "France", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Marseille Fos", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Marseille Fos Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "marseille", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FRMRS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Greece", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Santorini (Thira)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Aegean Sea", + "slug": "santorini", + "stepFreeAccess": null, + "terminalName": "Old Port Skala (Tender Anchorage & Cable Car)", + "unLocode": "GRJTR", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port Tampa Bay", + "negativeIntelligence": [], + "officialSource": null, + "region": "Florida / Gulf Coast", + "slug": "tampa", + "stepFreeAccess": null, + "terminalName": "Cruise Terminals 2, 3, 6", + "unLocode": "USTPA", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Belgium", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Zeebrugge (Bruges Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "zeebrugge", + "stepFreeAccess": null, + "terminalName": "Zweedse Kaai Cruise Terminal", + "unLocode": "BEZEE", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Latvia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Riga", + "negativeIntelligence": [], + "officialSource": null, + "region": "Baltic Sea", + "slug": "riga", + "stepFreeAccess": null, + "terminalName": "Riga Passenger Terminal (Vanšu Bridge)", + "unLocode": "LVRIX", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Denmark", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Copenhagen", + "negativeIntelligence": [], + "officialSource": null, + "region": "Baltic Sea", + "slug": "copenhagen", + "stepFreeAccess": null, + "terminalName": "Oceankaj (Ocean Quay Terminals 1-3) & Langelinie", + "unLocode": "DKCPH", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Mexico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Mexican Riviera.", - "name": "Port of Mazatlán (Sinaloa)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Mazatlán (Sinaloa) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Puerto Vallarta (Jalisco)", + "negativeIntelligence": [], + "officialSource": null, "region": "Mexican Riviera", - "slug": "mazatlan", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MZMZT", - "walkingTimeMin": 10 + "slug": "puerto-vallarta", + "stepFreeAccess": null, + "terminalName": "Puerto Mágico Cruise Terminal", + "unLocode": "MXPVR", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Central Mediterranean.", - "name": "Port of Messina (Sicily)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Messina (Sicily) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Central Mediterranean", - "slug": "messina", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITMSN", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "France", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ajaccio (Corsica)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "ajaccio", + "stepFreeAccess": null, + "terminalName": "Gare Maritime d'Ajaccio (Quai l'Herminier)", + "unLocode": "FRAJA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Florida / Caribbean.", - "name": "PortMiami (Cruise Capital)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "PortMiami (Cruise Capital) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Florida / Caribbean", - "slug": "miami", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USMIA", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Netherlands", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Cruise Port Rotterdam", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "rotterdam", + "stepFreeAccess": null, + "terminalName": "Wilhelminakade (Historic Holland America Line HQ)", + "unLocode": "NLRTM", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Monaco", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port Hercules (Monaco)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port Hercules (Monaco) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", "slug": "monaco", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Nouvelle Digue Flottante (Floating Pier)", "unLocode": "MCMON", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Greece", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Aegean Sea.", - "name": "Port of Mykonos (Tourlos)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Mykonos (Tourlos) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Aegean Sea", - "slug": "mykonos", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GRJMK", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Switzerland", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Basel (Rhine Hub)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Rhine River", + "slug": "basel", + "stepFreeAccess": null, + "terminalName": "St. Johann & Dreiländereck Piers", + "unLocode": "CHBSL", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Naples (Napoli)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Naples (Napoli) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Genoa (Genova)", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "naples", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITNAP", - "walkingTimeMin": 10 + "slug": "genoa", + "stepFreeAccess": null, + "terminalName": "Stazione Marittima (Ponte dei Mille)", + "unLocode": "ITGOA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Bahamas", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Bahamas / Caribbean.", - "name": "Nassau Cruise Port (Bahamas)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Nassau Cruise Port (Bahamas) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Bahamas / Caribbean", - "slug": "nassau", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "BSNAS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Hungary", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Budapest (Danube River)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Danube River", + "slug": "budapest", + "stepFreeAccess": null, + "terminalName": "Belgrád Rakpart & Vigadó Pier (Parliament View)", + "unLocode": "HUBUD", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Gulf Coast / Mississippi.", - "name": "Port of New Orleans", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of New Orleans Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Gulf Coast / Mississippi", - "slug": "new-orleans", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USMSY", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Argentina", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Buenos Aires (Benito Quinquela Martín)", + "negativeIntelligence": [], + "officialSource": null, + "region": "South America", + "slug": "buenos-aires", + "stepFreeAccess": null, + "terminalName": "Terminal de Cruceros Benito Quinquela Martín", + "unLocode": "ARBUE", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for East Coast / Atlantic.", - "name": "Port of New York (Manhattan/Brooklyn)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of New York (Manhattan/Brooklyn) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "East Coast / Atlantic", - "slug": "new-york", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USNYC", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Mexico", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Mazatlán (Sinaloa)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Mexican Riviera", + "slug": "mazatlan", + "stepFreeAccess": null, + "terminalName": "Mazatlán Cruise Terminal (Blue Line Walk)", + "unLocode": "MZMZT", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "France", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Villefranche-sur-Mer / Nice", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Villefranche-sur-Mer / Nice Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Cagliari (Sardinia)", + "negativeIntelligence": [], + "officialSource": null, "region": "Western Mediterranean", - "slug": "nice-villefranche", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FRVFR", - "walkingTimeMin": 10 + "slug": "cagliari", + "stepFreeAccess": null, + "terminalName": "Molo Rinascita & Molo Sabaudo", + "unLocode": "ITCAG", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Jamaica", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Caribbean.", - "name": "Port of Ocho Rios (Jamaica)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ocho Rios (Jamaica) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Caribbean", - "slug": "ocho-rios", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "JMOCH", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Canada", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Vancouver (Canada Place)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Pacific Northwest / Alaska", + "slug": "vancouver", + "stepFreeAccess": null, + "terminalName": "Canada Place Cruise Ship Terminal", + "unLocode": "CAVAN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Aruba", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Southern Caribbean.", - "name": "Port of Oranjestad (Aruba)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Oranjestad (Aruba) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Southern Caribbean", - "slug": "oranjestad", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "AWORJ", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Austria", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Vienna (Wien / Danube)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Danube River", + "slug": "vienna", + "stepFreeAccess": null, + "terminalName": "Reichsbrücke & Handelskai River Piers", + "unLocode": "ATVIE", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Norwegian Fjords.", - "name": "Port of Oslo", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Oslo Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Norwegian Fjords", - "slug": "oslo", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NOOSL", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Finland", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Helsinki", + "negativeIntelligence": [], + "officialSource": null, + "region": "Baltic Sea", + "slug": "helsinki", + "stepFreeAccess": null, + "terminalName": "Hernesaari Cruise Berths LHB/LHC & West Harbour", + "unLocode": "FIHEL", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Palermo", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Palermo Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "palermo", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITPMO", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "US Virgin Islands", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of St. Thomas (Charlotte Amalie)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Eastern Caribbean", + "slug": "st-thomas", + "stepFreeAccess": null, + "terminalName": "West Indian Company Dock (Havensight) & Crown Bay", + "unLocode": "VISTT", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Palma de Mallorca", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Palma de Mallorca Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "palma-de-mallorca", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESPMI", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Germany", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Columbus Cruise Center Bremerhaven (CCCB)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "bremerhaven", + "stepFreeAccess": null, + "terminalName": "Columbus Cruise Center Berths 1-3", + "unLocode": "DEBRV", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Danube River.", - "name": "Port of Passau (Three Rivers City / Danube)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Passau (Three Rivers City / Danube) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Danube River", - "slug": "passau", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DEPAS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Livorno (Florence/Pisa Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "livorno", + "stepFreeAccess": null, + "terminalName": "Porto Mediceo & Molo Italia", + "unLocode": "ITLIV", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Portugal", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Douro River.", - "name": "Pinhão River Pier (Douro Valley)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Pinhão River Pier (Douro Valley) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Douro River", - "slug": "pinhao", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "PTPNH", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Australia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Sydney (Overseas Passenger Terminal)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Australia & Pacific", + "slug": "sydney", + "stepFreeAccess": null, + "terminalName": "Circular Quay OPT (Direct Opera House View)", + "unLocode": "AUSYD", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Greece", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Aegean / Eastern Med.", - "name": "Port of Piraeus (Athens)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Piraeus (Athens) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Aegean / Eastern Med", - "slug": "piraeus", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GRPIR", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Argentina", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ushuaia (Antarctica Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "South America / Patagonia", + "slug": "ushuaia", + "stepFreeAccess": null, + "terminalName": "Muelle Comercial Ushuaia", + "unLocode": "ARUSH", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Florida / Caribbean.", - "name": "Port Canaveral (Orlando Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port Canaveral (Orlando Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Florida / Caribbean", - "slug": "port-canaveral", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USPCN", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Spain", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Malaga", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "malaga", + "stepFreeAccess": null, + "terminalName": "Muelle de Levante Terminals A & B", + "unLocode": "ESAGP", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Florida / Caribbean.", - "name": "Port Everglades (Fort Lauderdale)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port Everglades (Fort Lauderdale) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Florida / Caribbean", - "slug": "port-everglades", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USPEF", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Sweden", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Stockholm", + "negativeIntelligence": [], + "officialSource": null, + "region": "Baltic Sea", + "slug": "stockholm", + "stepFreeAccess": null, + "terminalName": "Frihamnen, Värtahamnen & Stadsgården", + "unLocode": "SESTO", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Portugal", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Douro River.", - "name": "Port of Porto / Douro River", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Porto / Douro River Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Douro River", - "slug": "porto", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "PTOPO", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Italy", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Palermo", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "palermo", + "stepFreeAccess": null, + "terminalName": "Molo Vittorio Veneto Terminal", + "unLocode": "ITPMO", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Mexico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Mexican Riviera.", - "name": "Port of Puerto Vallarta (Jalisco)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Puerto Vallarta (Jalisco) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Mexican Riviera", - "slug": "puerto-vallarta", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MXPVR", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Greece", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Mykonos (Tourlos)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Aegean Sea", + "slug": "mykonos", + "stepFreeAccess": null, + "terminalName": "New Port of Tourlos & SeaBus Transfer", + "unLocode": "GRJMK", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Portugal", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Douro River.", - "name": "Peso da Régua (Douro Valley)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Peso da Régua (Douro Valley) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Douro River", - "slug": "regua", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "PTREG", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Germany", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Hamburg", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "hamburg", + "stepFreeAccess": null, + "terminalName": "Cruise Center Altona, HafenCity & Steinwerder", + "unLocode": "DEHAM", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Iceland", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Atlantic / Iceland.", - "name": "Port of Reykjavik", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Reykjavik Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Atlantic / Iceland", - "slug": "reykjavik", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ISREY", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Galveston", + "negativeIntelligence": [], + "officialSource": null, + "region": "Texas / Gulf Coast", + "slug": "galveston", + "stepFreeAccess": null, + "terminalName": "Cruise Terminals 10, 25, 28", + "unLocode": "USGLS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Greece", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Aegean Sea.", - "name": "Port of Rhodes", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Rhodes Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Aegean Sea", - "slug": "rhodes", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GRRHO", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Hong Kong", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Kai Tak Cruise Terminal (Hong Kong)", + "negativeIntelligence": [], + "officialSource": null, + "region": "East Asia", + "slug": "hong-kong", + "stepFreeAccess": null, + "terminalName": "Kai Tak Runway Berths", + "unLocode": "HKHKG", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Latvia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", - "name": "Port of Riga", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Riga Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Germany", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Warnemünde (Berlin Gateway)", + "negativeIntelligence": [], + "officialSource": null, "region": "Baltic Sea", - "slug": "riga", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "LVRIX", - "walkingTimeMin": 10 + "slug": "warnemunde-rostock", + "stepFreeAccess": null, + "terminalName": "Warnemünde Cruise Center P7/P8", + "unLocode": "DEWAR", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Honduras", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Caribbean.", - "name": "Port of Roatan (Coxen Hole & Mahogany Bay)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Roatan (Coxen Hole & Mahogany Bay) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Caribbean", - "slug": "roatan", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "HNRTB", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Norway", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Oslo", + "negativeIntelligence": [], + "officialSource": null, + "region": "Norwegian Fjords", + "slug": "oslo", + "stepFreeAccess": null, + "terminalName": "Søndre Akershuskai (Below Akershus Fortress)", + "unLocode": "NOOSL", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Netherlands", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Cruise Port Rotterdam", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Cruise Port Rotterdam Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "rotterdam", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NLRTM", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of New York (Manhattan/Brooklyn)", + "negativeIntelligence": [], + "officialSource": null, + "region": "East Coast / Atlantic", + "slug": "new-york", + "stepFreeAccess": null, + "terminalName": "Manhattan (Piers 88/90) & Brooklyn (Pier 12)", + "unLocode": "USNYC", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Puerto Rico", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Eastern Caribbean.", - "name": "Port of San Juan (Puerto Rico)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of San Juan (Puerto Rico) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Eastern Caribbean", - "slug": "san-juan", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "PRSJU", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Turkey", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Galataport Istanbul", + "negativeIntelligence": [], + "officialSource": null, + "region": "Bosphorus / Black Sea", + "slug": "istanbul", + "stepFreeAccess": null, + "terminalName": "Galataport Underground Cruise Terminal", + "unLocode": "TRIST", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Spain", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Las Palmas (Gran Canaria)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Canary Islands", + "slug": "las-palmas", + "stepFreeAccess": null, + "terminalName": "Muelle Santa Catalina", + "unLocode": "ESLPA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Canary Islands.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Santa Cruz de Tenerife", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Santa Cruz de Tenerife Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Canary Islands", "slug": "santa-cruz-de-tenerife", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Muelle de Ribera Cruise Terminal", "unLocode": "ESTCI", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Greece", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Aegean Sea.", - "name": "Port of Santorini (Thira)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Santorini (Thira) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Aegean Sea", - "slug": "santorini", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GRJTR", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United Kingdom", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Southampton", + "negativeIntelligence": [], + "officialSource": null, + "region": "Northern Europe", + "slug": "southampton", + "stepFreeAccess": null, + "terminalName": "Horizon, Mayflower, Ocean & City Cruise Terminals", + "unLocode": "GBSOU", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Pacific Northwest / Alaska.", - "name": "Port of Seattle (Alaska Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Seattle (Alaska Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Pacific Northwest / Alaska", - "slug": "seattle", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USSEA", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Boston (Flynn Cruiseport)", + "negativeIntelligence": [], + "officialSource": null, + "region": "New England", + "slug": "boston", + "stepFreeAccess": null, + "terminalName": "Flynn Cruiseport Boston (Black Falcon Ave)", + "unLocode": "USBOS", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "China", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for East Asia.", - "name": "Shanghai Wusongkou International Cruise Terminal", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Shanghai Wusongkou International Cruise Terminal Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "East Asia", - "slug": "shanghai", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "CNSHG", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "France", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Strasbourg (Rhine)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Rhine River", + "slug": "strasbourg", + "stepFreeAccess": null, + "terminalName": "Parc du Rhin & Rue du Havre River Pier", + "unLocode": "FRSXB", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port Everglades (Fort Lauderdale)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Florida / Caribbean", + "slug": "port-everglades", + "stepFreeAccess": null, + "terminalName": "Terminal 25 & 18", + "unLocode": "USPEF", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Portugal", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Peso da Régua (Douro Valley)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Douro River", + "slug": "regua", + "stepFreeAccess": null, + "terminalName": "Cais da Régua (Douro Wine Museum)", + "unLocode": "PTREG", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "PortMiami (Cruise Capital)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Florida / Caribbean", + "slug": "miami", + "stepFreeAccess": null, + "terminalName": "Terminals A, AA, B, C, D, E, F, G, J, V", + "unLocode": "USMIA", + "walkingTimeMin": null + }, + { + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Spain", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Barcelona", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "barcelona", + "stepFreeAccess": null, + "terminalName": "Moll Adossat (Terminals A-E Helix)", + "unLocode": "ESBCN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Singapore", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Southeast Asia.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Singapore Marina Bay Cruise Centre (MBCCS)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Singapore Marina Bay Cruise Centre (MBCCS) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Southeast Asia", "slug": "singapore", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Marina Bay Cruise Centre Singapore", "unLocode": "SGSIN", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Alaska Inside Passage.", - "name": "Port of Skagway (Alaska)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Skagway (Alaska) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Ketchikan (Alaska)", + "negativeIntelligence": [], + "officialSource": null, "region": "Alaska Inside Passage", - "slug": "skagway", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USSGY", - "walkingTimeMin": 10 + "slug": "ketchikan", + "stepFreeAccess": null, + "terminalName": "Berths 1, 2, 3, 4 & Ward Cove", + "unLocode": "USKTN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "United Kingdom", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Port of Southampton", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Southampton Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "France", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Le Havre (Paris Gateway)", + "negativeIntelligence": [], + "officialSource": null, "region": "Northern Europe", - "slug": "southampton", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "GBSOU", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Croatia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Split", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Split Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "split", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "HRSPU", - "walkingTimeMin": 10 + "slug": "le-havre", + "stepFreeAccess": null, + "terminalName": "Pointe de Floride Cruise Hub", + "unLocode": "FRLEH", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Sint Maarten", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Eastern Caribbean.", - "name": "Port of St. Maarten (Philipsburg)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of St. Maarten (Philipsburg) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Eastern Caribbean", - "slug": "st-maarten", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "SXMMA", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Mexico", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Costa Maya (Mahahual)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Caribbean", + "slug": "costa-maya", + "stepFreeAccess": null, + "terminalName": "Puerto Costa Maya Cruise Facility", + "unLocode": "MXCMY", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "US Virgin Islands", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Eastern Caribbean.", - "name": "Port of St. Thomas (Charlotte Amalie)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of St. Thomas (Charlotte Amalie) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Eastern Caribbean", - "slug": "st-thomas", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "VISTT", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Seattle (Alaska Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Pacific Northwest / Alaska", + "slug": "seattle", + "stepFreeAccess": null, + "terminalName": "Bell Street Pier 66 & Smith Cove Pier 91", + "unLocode": "USSEA", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Norwegian Fjords.", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, "name": "Port of Stavanger", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Stavanger Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "negativeIntelligence": [], + "officialSource": null, "region": "Norwegian Fjords", "slug": "stavanger", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", + "stepFreeAccess": null, + "terminalName": "Strandkaien & Skagenkaien (Old Stavanger)", "unLocode": "NOSVG", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Sweden", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", - "name": "Port of Stockholm", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Stockholm Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Baltic Sea", - "slug": "stockholm", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "SESTO", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "France", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Rhine River.", - "name": "Port of Strasbourg (Rhine)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Strasbourg (Rhine) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Rhine River", - "slug": "strasbourg", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "FRSXB", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Australia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Australia & Pacific.", - "name": "Port of Sydney (Overseas Passenger Terminal)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Sydney (Overseas Passenger Terminal) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Australia & Pacific", - "slug": "sydney", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "AUSYD", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Estonia", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", - "name": "Port of Tallinn", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Tallinn Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Baltic Sea", - "slug": "tallinn", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "EETLL", - "walkingTimeMin": 10 + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "United States", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Florida / Gulf Coast.", - "name": "Port Tampa Bay", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port Tampa Bay Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Florida / Gulf Coast", - "slug": "tampa", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "USTPA", - "walkingTimeMin": 10 - }, - { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Trieste (Molo Bersaglieri)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Trieste (Molo Bersaglieri) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "trieste", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITTRS", - "walkingTimeMin": 10 + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port Canaveral (Orlando Gateway)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Florida / Caribbean", + "slug": "port-canaveral", + "stepFreeAccess": null, + "terminalName": "Cruise Terminals 1, 3, 5, 6, 8, 10", + "unLocode": "USPCN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Norway", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Arctic Norway.", - "name": "Port of Tromsø (Arctic Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Tromsø (Arctic Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Arctic Norway", - "slug": "tromso", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "NOTOS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Curaçao", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Willemstad (Curaçao)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Southern Caribbean", + "slug": "willemstad", + "stepFreeAccess": null, + "terminalName": "Mega Pier 1 & 2 (Tula/Jackie) & Mathey Wharf", + "unLocode": "CWWIL", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Argentina", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for South America / Patagonia.", - "name": "Port of Ushuaia (Antarctica Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ushuaia (Antarctica Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "South America / Patagonia", - "slug": "ushuaia", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ARUSH", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "China", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Shanghai Wusongkou International Cruise Terminal", + "negativeIntelligence": [], + "officialSource": null, + "region": "East Asia", + "slug": "shanghai", + "stepFreeAccess": null, + "terminalName": "Baoshan Wusongkou Terminal", + "unLocode": "CNSHG", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Spain", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Western Mediterranean.", - "name": "Port of Valencia", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Valencia Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Western Mediterranean", - "slug": "valencia", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ESVLC", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Croatia", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Dubrovnik (Gruž)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Adriatic Sea", + "slug": "dubrovnik", + "stepFreeAccess": null, + "terminalName": "Luka Gruž Cruise Terminal (Pier 7-10)", + "unLocode": "HRDBV", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Malta", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Central Mediterranean.", - "name": "Grand Harbour (Valletta, Malta)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Grand Harbour (Valletta, Malta) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Central Mediterranean", - "slug": "valletta", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "MTMLA", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Greece", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Heraklion (Crete)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Eastern Mediterranean", + "slug": "heraklion", + "stepFreeAccess": null, + "terminalName": "Heraklion Passenger Terminal (Piers 4-5)", + "unLocode": "GRHER", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, "country": "Canada", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Pacific Northwest / Alaska.", - "name": "Port of Vancouver (Canada Place)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Vancouver (Canada Place) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Victoria (Ogden Point)", + "negativeIntelligence": [], + "officialSource": null, "region": "Pacific Northwest / Alaska", - "slug": "vancouver", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "CAVAN", - "walkingTimeMin": 10 + "slug": "victoria", + "stepFreeAccess": null, + "terminalName": "Ogden Point Terminal (Piers A & B)", + "unLocode": "CAVIC", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Ravenna (Venice Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Ravenna (Venice Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "venice-ravenna", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITRAN", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "United States", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Cape Liberty Cruise Port (Bayonne)", + "negativeIntelligence": [], + "officialSource": null, + "region": "East Coast / New York Harbour", + "slug": "bayonne-cape-liberty", + "stepFreeAccess": null, + "terminalName": "Cape Liberty Terminal", + "unLocode": "USBYN", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Italy", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Adriatic Sea.", - "name": "Port of Trieste (Venice Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Trieste (Venice Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Adriatic Sea", - "slug": "venice-trieste", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ITTRS", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Greece", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Piraeus (Athens)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Aegean / Eastern Med", + "slug": "piraeus", + "stepFreeAccess": null, + "terminalName": "Piraeus Cruise Terminal (MIAOULIS Terminal A/B/C)", + "unLocode": "GRPIR", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Canada", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Pacific Northwest / Alaska.", - "name": "Port of Victoria (Ogden Point)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Victoria (Ogden Point) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Pacific Northwest / Alaska", - "slug": "victoria", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "CAVIC", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Honduras", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Roatan (Coxen Hole & Mahogany Bay)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Caribbean", + "slug": "roatan", + "stepFreeAccess": null, + "terminalName": "Port of Roatan & Mahogany Bay Carnival Pier", + "unLocode": "HNRTB", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Austria", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Danube River.", - "name": "Port of Vienna (Wien / Danube)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Vienna (Wien / Danube) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Danube River", - "slug": "vienna", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "ATVIE", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Cayman Islands", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Grand Cayman (George Town)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Caribbean", + "slug": "grand-cayman", + "stepFreeAccess": null, + "terminalName": "George Town Tender Terminals (North/South/Royal)", + "unLocode": "KYGEC", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Germany", - "currency": "Euro (€ / EUR)", - "distanceToCenterM": 500, - "emergencyPhone": "112", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Baltic Sea.", - "name": "Port of Warnemünde (Berlin Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Warnemünde (Berlin Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Baltic Sea", - "slug": "warnemunde-rostock", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "DEWAR", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "France", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Cannes", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "cannes", + "stepFreeAccess": null, + "terminalName": "Gare Maritime (Tender Anchorage in Bay)", + "unLocode": "FRCEQ", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Curaçao", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Southern Caribbean.", - "name": "Port of Willemstad (Curaçao)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Willemstad (Curaçao) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Southern Caribbean", - "slug": "willemstad", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "CWWIL", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Spain", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Palma de Mallorca", + "negativeIntelligence": [], + "officialSource": null, + "region": "Western Mediterranean", + "slug": "palma-de-mallorca", + "stepFreeAccess": null, + "terminalName": "Estación Marítima (Muelle de Poniente)", + "unLocode": "ESPMI", + "walkingTimeMin": null }, { - "airportTransit": "Regional airport connection available via express bus or taxi.", - "berths": [ - "Berth 1", - "Berth 2" - ], - "callingShips": [ - { - "name": "MSC Bellissima", - "slug": "msc-bellissima" - }, - { - "name": "MSC World Europa", - "slug": "msc-world-europa" - }, - { - "name": "MSC Meraviglia", - "slug": "msc-meraviglia" - } - ], - "cardAcceptancePct": 98, - "country": "Belgium", - "currency": "USD ($)", - "distanceToCenterM": 500, - "emergencyPhone": "911", - "gangwayDeckDefault": 5, - "headline": "Strategic maritime cruise port gateway for Northern Europe.", - "name": "Port of Zeebrugge (Bruges Gateway)", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": "Port of Zeebrugge (Bruges Gateway) Port Authority", - "trustLevel": "OFFICIAL", - "url": "https://www.timonelo.com" - }, - "region": "Northern Europe", - "slug": "zeebrugge", - "stepFreeAccess": true, - "terminalName": "Cruise Terminal", - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "unLocode": "BEZEE", - "walkingTimeMin": 10 + "berths": [], + "callingShips": [], + "cardAcceptancePct": null, + "country": "Greece", + "currency": null, + "distanceToCenterM": null, + "emergencyPhone": null, + "gangwayDeckDefault": null, + "name": "Port of Corfu (Kerkyra)", + "negativeIntelligence": [], + "officialSource": null, + "region": "Ionian Sea", + "slug": "corfu", + "stepFreeAccess": null, + "terminalName": "New Port of Corfu Passenger Terminal", + "unLocode": "GRCFU", + "walkingTimeMin": null } ]; -export function getPortBySlug(slug: string): PortData { - const found = PORTS_REGISTRY.find((p) => p.slug === slug); - return found || PORTS_REGISTRY[0]; +// Returns undefined for an unknown slug. Returning PORTS_REGISTRY[0] would +// silently present one port's data under another port's name. +export function getPortBySlug(slug: string): PortData | undefined { + return PORTS_REGISTRY.find((p) => p.slug === slug); } diff --git a/frontend/src/ports.ts b/frontend/src/ports.ts index 24852b9..038d7fe 100644 --- a/frontend/src/ports.ts +++ b/frontend/src/ports.ts @@ -7,26 +7,28 @@ export interface CuratedPort { slug: string; name: string; shortName: string; - unLocode: string; - country: string; - region: string; + unLocode: string | null; + country: string | null; + region: string | null; headlineEn: string; headlineDe: string; storyEn: string; storyDe: string; - terminalPier: string; + // Operational passenger facts. Null until the knowledge layer carries + // field-scoped evidence; see the wiring note below. + terminalPier: string | null; gangwayDeck: number | null; distanceToCenterKm: number | null; walkingTimeMin: number | null; - stepFreeAccess: boolean; - transitNoteEn: string; - transitNoteDe: string; - airportTransitEn: string; - airportTransitDe: string; - currency: string; - cardAcceptancePct: number; - emergencyPhone: string; - policePhone: string; + stepFreeAccess: boolean | null; + transitNoteEn: string | null; + transitNoteDe: string | null; + airportTransitEn: string | null; + airportTransitDe: string | null; + currency: string | null; + cardAcceptancePct: number | null; + emergencyPhone: string | null; + policePhone: string | null; callingShips: { slug: string; name: string }[]; timEssentialsDe: string[]; timEssentialsEn: string[]; @@ -55,8 +57,8 @@ const CURATED_PORT_STORIES: Record p.slug === slug); + // Entity fields come from the knowledge layer or not at all. The previous + // fallbacks invented data for any port the knowledge layer did not know: + // `slug.toUpperCase()` rendered "YOKOHAMA" in the UN/LOCODE field, and + // 'Europe / Global' / 'Mediterranean & River' / 'EUR (€)' / 98 were + // presentation defaults dressed as facts. Null renders as unavailable. return { slug, - name: raw ? raw.name : custom.shortName, + name: raw?.name ?? custom.shortName, shortName: custom.shortName, - unLocode: raw ? raw.unLocode : slug.toUpperCase(), - country: raw ? raw.country : 'Europe / Global', - region: raw ? raw.region : 'Mediterranean & River', + unLocode: raw?.unLocode ?? null, + country: raw?.country ?? null, + region: raw?.region ?? null, headlineDe: custom.headlineDe, headlineEn: custom.headlineEn, storyDe: custom.storyDe, storyEn: custom.storyEn, - terminalPier: custom.terminalPier, - gangwayDeck: custom.gangwayDeck, - distanceToCenterKm: custom.distanceKm, - walkingTimeMin: custom.walkingMin, - stepFreeAccess: true, - transitNoteDe: custom.transitDe, - transitNoteEn: custom.transitEn, - airportTransitDe: custom.airportDe, - airportTransitEn: custom.airportEn, - currency: raw ? raw.currency : 'EUR (€)', - cardAcceptancePct: raw ? raw.cardAcceptancePct : 98, - emergencyPhone: custom.emergency, - policePhone: custom.police, + // CURATED_PORT_STORIES holds hand-written values with no provenance model. + // Descriptive copy (shortName, headline, story) is editorial framing and + // stays. The operational facts below do not: a gangway deck, a walking + // time, a terminal assignment or an emergency number changes what a + // passenger does, so each needs evidence and none has any. They are wired + // to null rather than deleted from the source block, so the values remain + // available as candidates when a sourced port pipeline exists. + terminalPier: null, + gangwayDeck: null, + distanceToCenterKm: null, + walkingTimeMin: null, + stepFreeAccess: null, + transitNoteDe: null, + transitNoteEn: null, + airportTransitDe: null, + airportTransitEn: null, + currency: raw?.currency ?? null, + cardAcceptancePct: raw?.cardAcceptancePct ?? null, + emergencyPhone: null, + policePhone: null, callingShips, - timEssentialsDe: custom.essentialsDe, - timEssentialsEn: custom.essentialsEn, + timEssentialsDe: [], + timEssentialsEn: [], }; }); -export function getPortBySlug(slug: string): CuratedPort { - const found = PORTS_REGISTRY.find((p) => p.slug === slug); - return found || PORTS_REGISTRY[0]; +// Returns undefined for an unknown slug rather than silently presenting the +// first port's data under the requested name. +export function getPortBySlug(slug: string): CuratedPort | undefined { + return PORTS_REGISTRY.find((p) => p.slug === slug); } diff --git a/knowledge/ports/ajaccio/identity.json b/knowledge/ports/ajaccio/identity.json index caf6399..b1deb2d 100644 --- a/knowledge/ports/ajaccio/identity.json +++ b/knowledge/ports/ajaccio/identity.json @@ -8,35 +8,22 @@ "latitude": 41.92, "longitude": 8.74 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Gare Maritime d'Ajaccio (Quai l'Herminier)", - "berths": [ - "Ajaccio Berth 1", - "Ajaccio Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Ajaccio.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/akureyri/identity.json b/knowledge/ports/akureyri/identity.json index 9a96119..1494f16 100644 --- a/knowledge/ports/akureyri/identity.json +++ b/knowledge/ports/akureyri/identity.json @@ -8,35 +8,22 @@ "latitude": 65.68, "longitude": -18.085 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Oddeyrarbryggja & Tangabryggja", - "berths": [ - "Akureyri Berth 1", - "Akureyri Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Akureyri.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/alesund/identity.json b/knowledge/ports/alesund/identity.json index b87e5a1..cbeffe6 100644 --- a/knowledge/ports/alesund/identity.json +++ b/knowledge/ports/alesund/identity.json @@ -8,35 +8,22 @@ "latitude": 62.472, "longitude": 6.155 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Prestebrygga & Skansekai (Art Nouveau Center)", - "berths": [ - "Alesund Berth 1", - "Alesund Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Ålesund.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/amsterdam/identity.json b/knowledge/ports/amsterdam/identity.json index 5bf89a3..ef99e45 100644 --- a/knowledge/ports/amsterdam/identity.json +++ b/knowledge/ports/amsterdam/identity.json @@ -8,35 +8,22 @@ "latitude": 52.378, "longitude": 4.915 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Passenger Terminal Amsterdam (Piet Heinkade)", - "berths": [ - "Amsterdam Berth 1", - "Amsterdam Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Passenger Terminal Amsterdam.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/arrecife/identity.json b/knowledge/ports/arrecife/identity.json index 93128fb..0869672 100644 --- a/knowledge/ports/arrecife/identity.json +++ b/knowledge/ports/arrecife/identity.json @@ -8,35 +8,22 @@ "latitude": 28.96, "longitude": -13.54 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle de Los Mármoles & Muelle de Cruceros", - "berths": [ - "Arrecife Berth 1", - "Arrecife Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Arrecife.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/barcelona/identity.json b/knowledge/ports/barcelona/identity.json index 979f9e0..64521f6 100644 --- a/knowledge/ports/barcelona/identity.json +++ b/knowledge/ports/barcelona/identity.json @@ -8,35 +8,22 @@ "latitude": 41.35, "longitude": 2.17 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Moll Adossat (Terminals A-E Helix)", - "berths": [ - "Barcelona Berth 1", - "Barcelona Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Barcelona.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/bari/identity.json b/knowledge/ports/bari/identity.json index e7f83d8..7add8ee 100644 --- a/knowledge/ports/bari/identity.json +++ b/knowledge/ports/bari/identity.json @@ -8,34 +8,22 @@ "latitude": 41.135, "longitude": 16.865 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Banchina di Ponente & Molo San Vito", - "berths": [ - "Bari Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Bari.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/basel/identity.json b/knowledge/ports/basel/identity.json index 774e983..62d1b0f 100644 --- a/knowledge/ports/basel/identity.json +++ b/knowledge/ports/basel/identity.json @@ -8,35 +8,22 @@ "latitude": 47.585, "longitude": 7.59 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "St. Johann & Dreiländereck Piers", - "berths": [ - "Basel Berth 1", - "Basel Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Basel.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/bayonne-cape-liberty/identity.json b/knowledge/ports/bayonne-cape-liberty/identity.json index 7d18e00..d9e95c1 100644 --- a/knowledge/ports/bayonne-cape-liberty/identity.json +++ b/knowledge/ports/bayonne-cape-liberty/identity.json @@ -8,35 +8,22 @@ "latitude": 40.665, "longitude": -74.075 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cape Liberty Terminal", - "berths": [ - "Bayonne-Cape-Liberty Berth 1", - "Bayonne-Cape-Liberty Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Cape Liberty Cruise Port.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/bergen/identity.json b/knowledge/ports/bergen/identity.json index b94f3a9..10a146c 100644 --- a/knowledge/ports/bergen/identity.json +++ b/knowledge/ports/bergen/identity.json @@ -8,35 +8,22 @@ "latitude": 60.395, "longitude": 5.315 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Skolten, Bontelabo & Jekteviksbukten", - "berths": [ - "Bergen Berth 1", - "Bergen Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Bergen.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/boston/identity.json b/knowledge/ports/boston/identity.json index ae83a81..8245f2b 100644 --- a/knowledge/ports/boston/identity.json +++ b/knowledge/ports/boston/identity.json @@ -8,35 +8,22 @@ "latitude": 42.342, "longitude": -71.032 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Flynn Cruiseport Boston (Black Falcon Ave)", - "berths": [ - "Boston Berth 1", - "Boston Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Boston.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/bratislava/identity.json b/knowledge/ports/bratislava/identity.json index 8db49fd..19e21b4 100644 --- a/knowledge/ports/bratislava/identity.json +++ b/knowledge/ports/bratislava/identity.json @@ -8,35 +8,22 @@ "latitude": 48.14, "longitude": 17.11 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Fajnorovo Nábrežie (Old Town Promenade)", - "berths": [ - "Bratislava Berth 1", - "Bratislava Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Bratislava.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/bremerhaven/identity.json b/knowledge/ports/bremerhaven/identity.json index 596e596..b184d88 100644 --- a/knowledge/ports/bremerhaven/identity.json +++ b/knowledge/ports/bremerhaven/identity.json @@ -8,34 +8,22 @@ "latitude": 53.56, "longitude": 8.56 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Columbus Cruise Center Berths 1-3", - "berths": [ - "Bremerhaven Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Columbus Cruise Center Bremerhaven.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/bridgetown/identity.json b/knowledge/ports/bridgetown/identity.json index 699f7ff..95d5bf2 100644 --- a/knowledge/ports/bridgetown/identity.json +++ b/knowledge/ports/bridgetown/identity.json @@ -8,35 +8,22 @@ "latitude": 13.105, "longitude": -59.625 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Bridgetown Cruise Terminal (Deep Water Harbour)", - "berths": [ - "Bridgetown Berth 1", - "Bridgetown Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Bridgetown.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/budapest/identity.json b/knowledge/ports/budapest/identity.json index eb089c3..43bf889 100644 --- a/knowledge/ports/budapest/identity.json +++ b/knowledge/ports/budapest/identity.json @@ -8,35 +8,22 @@ "latitude": 47.498, "longitude": 19.045 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Belgrád Rakpart & Vigadó Pier (Parliament View)", - "berths": [ - "Budapest Berth 1", - "Budapest Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Budapest.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/buenos-aires/identity.json b/knowledge/ports/buenos-aires/identity.json index 46a9ea2..06c30d6 100644 --- a/knowledge/ports/buenos-aires/identity.json +++ b/knowledge/ports/buenos-aires/identity.json @@ -8,34 +8,22 @@ "latitude": -34.585, "longitude": -58.37 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Terminal de Cruceros Benito Quinquela Martín", - "berths": [ - "Buenos-Aires Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Buenos Aires.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/cabo-san-lucas/identity.json b/knowledge/ports/cabo-san-lucas/identity.json index db6db1a..f78e233 100644 --- a/knowledge/ports/cabo-san-lucas/identity.json +++ b/knowledge/ports/cabo-san-lucas/identity.json @@ -8,34 +8,22 @@ "latitude": 22.88, "longitude": -109.91 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Marina Cabo Tender Pier (Land's End Arch)", - "berths": [ - "Cabo-San-Lucas Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "MXN", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Cabo San Lucas.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/cadiz/identity.json b/knowledge/ports/cadiz/identity.json index effc84e..7b502e9 100644 --- a/knowledge/ports/cadiz/identity.json +++ b/knowledge/ports/cadiz/identity.json @@ -8,35 +8,22 @@ "latitude": 36.5333, "longitude": -6.2833 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle Alfonso XIII (Direct Old Town Gate)", - "berths": [ - "Cadiz Berth 1", - "Cadiz Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Cadiz.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/cagliari/identity.json b/knowledge/ports/cagliari/identity.json index 4ce3678..3ef53ec 100644 --- a/knowledge/ports/cagliari/identity.json +++ b/knowledge/ports/cagliari/identity.json @@ -8,35 +8,22 @@ "latitude": 39.213, "longitude": 9.112 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Molo Rinascita & Molo Sabaudo", - "berths": [ - "Cagliari Berth 1", - "Cagliari Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Cagliari.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/cannes/identity.json b/knowledge/ports/cannes/identity.json index de7d780..c514f6a 100644 --- a/knowledge/ports/cannes/identity.json +++ b/knowledge/ports/cannes/identity.json @@ -8,35 +8,22 @@ "latitude": 43.55, "longitude": 7.0167 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Gare Maritime (Tender Anchorage in Bay)", - "berths": [ - "Cannes Berth 1", - "Cannes Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Cannes.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/castries/identity.json b/knowledge/ports/castries/identity.json index 0cccd5c..3a38b0f 100644 --- a/knowledge/ports/castries/identity.json +++ b/knowledge/ports/castries/identity.json @@ -8,35 +8,22 @@ "latitude": 14.015, "longitude": -60.995 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Pointe Seraphine & La Place Carenage", - "berths": [ - "Castries Berth 1", - "Castries Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Castries.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/civitavecchia/identity.json b/knowledge/ports/civitavecchia/identity.json index add4008..03e2d84 100644 --- a/knowledge/ports/civitavecchia/identity.json +++ b/knowledge/ports/civitavecchia/identity.json @@ -8,35 +8,22 @@ "latitude": 42.0933, "longitude": 11.7892 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Amerigo Vespucci Cruise Terminal (Quay 12/25)", - "berths": [ - "Civitavecchia Berth 1", - "Civitavecchia Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Civitavecchia.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/cologne/identity.json b/knowledge/ports/cologne/identity.json index 68d3ec1..e213e58 100644 --- a/knowledge/ports/cologne/identity.json +++ b/knowledge/ports/cologne/identity.json @@ -8,35 +8,22 @@ "latitude": 50.94, "longitude": 6.965 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Konrad-Adenauer-Ufer & Frankenwerft (Cathedral View)", - "berths": [ - "Cologne Berth 1", - "Cologne Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Cologne.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/copenhagen/identity.json b/knowledge/ports/copenhagen/identity.json index 3c7c2a9..740f8c3 100644 --- a/knowledge/ports/copenhagen/identity.json +++ b/knowledge/ports/copenhagen/identity.json @@ -8,35 +8,22 @@ "latitude": 55.705, "longitude": 12.6 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Oceankaj (Ocean Quay Terminals 1-3) & Langelinie", - "berths": [ - "Copenhagen Berth 1", - "Copenhagen Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Copenhagen.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/corfu/identity.json b/knowledge/ports/corfu/identity.json index 5802c73..d28cf53 100644 --- a/knowledge/ports/corfu/identity.json +++ b/knowledge/ports/corfu/identity.json @@ -8,35 +8,22 @@ "latitude": 39.625, "longitude": 19.905 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "New Port of Corfu Passenger Terminal", - "berths": [ - "Corfu Berth 1", - "Corfu Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Corfu.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/costa-maya/identity.json b/knowledge/ports/costa-maya/identity.json index 46344b7..da827d0 100644 --- a/knowledge/ports/costa-maya/identity.json +++ b/knowledge/ports/costa-maya/identity.json @@ -8,35 +8,22 @@ "latitude": 18.725, "longitude": -87.695 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Puerto Costa Maya Cruise Facility", - "berths": [ - "Costa-Maya Berth 1", - "Costa-Maya Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Costa Maya.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/cozumel/identity.json b/knowledge/ports/cozumel/identity.json index beaaddc..3027da5 100644 --- a/knowledge/ports/cozumel/identity.json +++ b/knowledge/ports/cozumel/identity.json @@ -8,35 +8,22 @@ "latitude": 20.485, "longitude": -86.975 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Punta Langosta, International Pier, Puerta Maya", - "berths": [ - "Cozumel Berth 1", - "Cozumel Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Cozumel.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/dover/identity.json b/knowledge/ports/dover/identity.json index 62e451b..162d1bd 100644 --- a/knowledge/ports/dover/identity.json +++ b/knowledge/ports/dover/identity.json @@ -8,35 +8,22 @@ "latitude": 51.12, "longitude": 1.32 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Dover Western Docks Terminals 1 & 2", - "berths": [ - "Dover Berth 1", - "Dover Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "GBP", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Dover.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/dubrovnik/identity.json b/knowledge/ports/dubrovnik/identity.json index b8eb8fc..9271155 100644 --- a/knowledge/ports/dubrovnik/identity.json +++ b/knowledge/ports/dubrovnik/identity.json @@ -8,35 +8,22 @@ "latitude": 42.66, "longitude": 18.085 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Luka Gruž Cruise Terminal (Pier 7-10)", - "berths": [ - "Dubrovnik Berth 1", - "Dubrovnik Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Dubrovnik.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/ensenada/identity.json b/knowledge/ports/ensenada/identity.json index b65cb4c..77e4cf3 100644 --- a/knowledge/ports/ensenada/identity.json +++ b/knowledge/ports/ensenada/identity.json @@ -8,34 +8,22 @@ "latitude": 31.855, "longitude": -116.62 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle de Cruceros Ensenada", - "berths": [ - "Ensenada Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "MXN", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Ensenada.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/flam/identity.json b/knowledge/ports/flam/identity.json index 9ae821a..6ba5d97 100644 --- a/knowledge/ports/flam/identity.json +++ b/knowledge/ports/flam/identity.json @@ -8,35 +8,22 @@ "latitude": 60.864, "longitude": 7.118 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Flåm Cruise Pier (Direct Flåmsbana Railway)", - "berths": [ - "Flam Berth 1", - "Flam Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Flåm.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/fort-lauderdale/identity.json b/knowledge/ports/fort-lauderdale/identity.json index dd22168..2085315 100644 --- a/knowledge/ports/fort-lauderdale/identity.json +++ b/knowledge/ports/fort-lauderdale/identity.json @@ -8,35 +8,22 @@ "latitude": 26.0864, "longitude": -80.1189 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Terminals 2, 4, 18, 19, 21, 25, 26, 29", - "berths": [ - "Fort-Lauderdale Berth 1", - "Fort-Lauderdale Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port Everglades.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/funchal/identity.json b/knowledge/ports/funchal/identity.json index b6a5925..cf04669 100644 --- a/knowledge/ports/funchal/identity.json +++ b/knowledge/ports/funchal/identity.json @@ -8,35 +8,22 @@ "latitude": 32.645, "longitude": -16.908 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cais Sul Cruise Terminal", - "berths": [ - "Funchal Berth 1", - "Funchal Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Funchal.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/galveston/identity.json b/knowledge/ports/galveston/identity.json index 603f43a..28e16b9 100644 --- a/knowledge/ports/galveston/identity.json +++ b/knowledge/ports/galveston/identity.json @@ -8,35 +8,22 @@ "latitude": 29.31, "longitude": -94.795 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cruise Terminals 10, 25, 28", - "berths": [ - "Galveston Berth 1", - "Galveston Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Galveston.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/geiranger/identity.json b/knowledge/ports/geiranger/identity.json index 40ece6a..13c3e85 100644 --- a/knowledge/ports/geiranger/identity.json +++ b/knowledge/ports/geiranger/identity.json @@ -8,35 +8,22 @@ "latitude": 62.102, "longitude": 7.205 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Geiranger SeaWalk Floating Pier & Tender", - "berths": [ - "Geiranger Berth 1", - "Geiranger Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Geiranger.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/genoa/identity.json b/knowledge/ports/genoa/identity.json index 9034eaa..88663c6 100644 --- a/knowledge/ports/genoa/identity.json +++ b/knowledge/ports/genoa/identity.json @@ -8,35 +8,22 @@ "latitude": 44.4072, "longitude": 8.9192 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Stazione Marittima (Ponte dei Mille)", - "berths": [ - "Genoa Berth 1", - "Genoa Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Genoa.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/grand-cayman/identity.json b/knowledge/ports/grand-cayman/identity.json index d0d4c90..5983e4a 100644 --- a/knowledge/ports/grand-cayman/identity.json +++ b/knowledge/ports/grand-cayman/identity.json @@ -8,35 +8,22 @@ "latitude": 19.295, "longitude": -81.385 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "George Town Tender Terminals (North/South/Royal)", - "berths": [ - "Grand-Cayman Berth 1", - "Grand-Cayman Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Grand Cayman.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/haifa/identity.json b/knowledge/ports/haifa/identity.json index 8d87944..031edbc 100644 --- a/knowledge/ports/haifa/identity.json +++ b/knowledge/ports/haifa/identity.json @@ -8,35 +8,22 @@ "latitude": 32.822, "longitude": 35.003 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Haifa Passenger Terminal", - "berths": [ - "Haifa Berth 1", - "Haifa Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Haifa.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/hamburg/identity.json b/knowledge/ports/hamburg/identity.json index 0dfa6ef..9359a58 100644 --- a/knowledge/ports/hamburg/identity.json +++ b/knowledge/ports/hamburg/identity.json @@ -8,35 +8,22 @@ "latitude": 53.535, "longitude": 9.98 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cruise Center Altona, HafenCity & Steinwerder", - "berths": [ - "Hamburg Berth 1", - "Hamburg Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Hamburg.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/helsinki/identity.json b/knowledge/ports/helsinki/identity.json index 72185cb..09e26b0 100644 --- a/knowledge/ports/helsinki/identity.json +++ b/knowledge/ports/helsinki/identity.json @@ -8,35 +8,22 @@ "latitude": 60.155, "longitude": 24.93 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Hernesaari Cruise Berths LHB/LHC & West Harbour", - "berths": [ - "Helsinki Berth 1", - "Helsinki Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Helsinki.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/heraklion/identity.json b/knowledge/ports/heraklion/identity.json index 970b322..ba20dae 100644 --- a/knowledge/ports/heraklion/identity.json +++ b/knowledge/ports/heraklion/identity.json @@ -8,35 +8,22 @@ "latitude": 35.343, "longitude": 25.148 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Heraklion Passenger Terminal (Piers 4-5)", - "berths": [ - "Heraklion Berth 1", - "Heraklion Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Heraklion.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/honDefault-nordkapp/identity.json b/knowledge/ports/honDefault-nordkapp/identity.json index 67764b8..63b7bd2 100644 --- a/knowledge/ports/honDefault-nordkapp/identity.json +++ b/knowledge/ports/honDefault-nordkapp/identity.json @@ -8,35 +8,22 @@ "latitude": 70.98, "longitude": 25.975 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Honningsvåg Pier (Bus to North Cape Hall)", - "berths": [ - "Hondefault-Nordkapp Berth 1", - "Hondefault-Nordkapp Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Honningsvåg.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/hong-kong/identity.json b/knowledge/ports/hong-kong/identity.json index 0265bf0..cbfad7a 100644 --- a/knowledge/ports/hong-kong/identity.json +++ b/knowledge/ports/hong-kong/identity.json @@ -8,34 +8,22 @@ "latitude": 22.308, "longitude": 114.213 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Kai Tak Runway Berths", - "berths": [ - "Hong-Kong Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "999" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Kai Tak Cruise Terminal.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/ibiza/identity.json b/knowledge/ports/ibiza/identity.json index 35800de..4d56ebf 100644 --- a/knowledge/ports/ibiza/identity.json +++ b/knowledge/ports/ibiza/identity.json @@ -8,35 +8,22 @@ "latitude": 38.91, "longitude": 1.44 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Dique del Botafoc", - "berths": [ - "Ibiza Berth 1", - "Ibiza Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Ibiza.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/istanbul/identity.json b/knowledge/ports/istanbul/identity.json index 4864682..a992e93 100644 --- a/knowledge/ports/istanbul/identity.json +++ b/knowledge/ports/istanbul/identity.json @@ -8,35 +8,22 @@ "latitude": 41.027, "longitude": 28.985 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Galataport Underground Cruise Terminal", - "berths": [ - "Istanbul Berth 1", - "Istanbul Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Galataport Istanbul.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/juneau/identity.json b/knowledge/ports/juneau/identity.json index fe633d6..0a5c9b3 100644 --- a/knowledge/ports/juneau/identity.json +++ b/knowledge/ports/juneau/identity.json @@ -8,35 +8,22 @@ "latitude": 58.298, "longitude": -134.405 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Franklin Dock, Cruise Ship Terminal, AJ Dock", - "berths": [ - "Juneau Berth 1", - "Juneau Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Juneau.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/ketchikan/identity.json b/knowledge/ports/ketchikan/identity.json index 37bb9dd..e6bd7a2 100644 --- a/knowledge/ports/ketchikan/identity.json +++ b/knowledge/ports/ketchikan/identity.json @@ -8,35 +8,22 @@ "latitude": 55.342, "longitude": -131.645 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Berths 1, 2, 3, 4 & Ward Cove", - "berths": [ - "Ketchikan Berth 1", - "Ketchikan Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Ketchikan.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/kiel/identity.json b/knowledge/ports/kiel/identity.json index ea0eaf3..a60db57 100644 --- a/knowledge/ports/kiel/identity.json +++ b/knowledge/ports/kiel/identity.json @@ -8,35 +8,22 @@ "latitude": 54.325, "longitude": 10.145 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Ostseekai & Ostuferhafen", - "berths": [ - "Kiel Berth 1", - "Kiel Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Kiel.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/koblenz/identity.json b/knowledge/ports/koblenz/identity.json index 09c9709..f284f53 100644 --- a/knowledge/ports/koblenz/identity.json +++ b/knowledge/ports/koblenz/identity.json @@ -8,35 +8,22 @@ "latitude": 50.363, "longitude": 7.605 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Konrad-Adenauer-Ufer Piers 1-9", - "berths": [ - "Koblenz Berth 1", - "Koblenz Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Koblenz.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/kotor/identity.json b/knowledge/ports/kotor/identity.json index 5fe5f82..2546b1c 100644 --- a/knowledge/ports/kotor/identity.json +++ b/knowledge/ports/kotor/identity.json @@ -8,35 +8,22 @@ "latitude": 42.425, "longitude": 18.769 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Luka Kotor (Main Pier & Fjord Anchorage)", - "berths": [ - "Kotor Berth 1", - "Kotor Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Kotor.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/kusadasi/identity.json b/knowledge/ports/kusadasi/identity.json index 1854f82..a521a6a 100644 --- a/knowledge/ports/kusadasi/identity.json +++ b/knowledge/ports/kusadasi/identity.json @@ -8,35 +8,22 @@ "latitude": 37.86, "longitude": 27.255 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Ege Port Kusadasi (Direct Bazaar Promenade)", - "berths": [ - "Kusadasi Berth 1", - "Kusadasi Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Kusadasi.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/la-spezia/identity.json b/knowledge/ports/la-spezia/identity.json index 713000a..0bc4e80 100644 --- a/knowledge/ports/la-spezia/identity.json +++ b/knowledge/ports/la-spezia/identity.json @@ -8,35 +8,22 @@ "latitude": 44.1025, "longitude": 9.8292 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Molo Garibaldi Cruise Terminal", - "berths": [ - "La-Spezia Berth 1", - "La-Spezia Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of La Spezia.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/las-palmas/identity.json b/knowledge/ports/las-palmas/identity.json index 303a344..128ac4e 100644 --- a/knowledge/ports/las-palmas/identity.json +++ b/knowledge/ports/las-palmas/identity.json @@ -8,35 +8,22 @@ "latitude": 28.14, "longitude": -15.425 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle Santa Catalina", - "berths": [ - "Las-Palmas Berth 1", - "Las-Palmas Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Las Palmas.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/le-havre/identity.json b/knowledge/ports/le-havre/identity.json index 45b804c..0a56a44 100644 --- a/knowledge/ports/le-havre/identity.json +++ b/knowledge/ports/le-havre/identity.json @@ -8,35 +8,22 @@ "latitude": 49.485, "longitude": 0.115 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Pointe de Floride Cruise Hub", - "berths": [ - "Le-Havre Berth 1", - "Le-Havre Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Le Havre.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/limassol/identity.json b/knowledge/ports/limassol/identity.json index b66e795..c3c7480 100644 --- a/knowledge/ports/limassol/identity.json +++ b/knowledge/ports/limassol/identity.json @@ -8,35 +8,22 @@ "latitude": 34.655, "longitude": 33.015 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "DP World Limassol Cruise Terminal", - "berths": [ - "Limassol Berth 1", - "Limassol Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Limassol.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/lisbon/identity.json b/knowledge/ports/lisbon/identity.json index aaf6d73..88df3f2 100644 --- a/knowledge/ports/lisbon/identity.json +++ b/knowledge/ports/lisbon/identity.json @@ -8,35 +8,22 @@ "latitude": 38.71, "longitude": -9.12 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Santa Apolónia / Jardim do Tabaco Terminal", - "berths": [ - "Lisbon Berth 1", - "Lisbon Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Lisbon.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/livorno/identity.json b/knowledge/ports/livorno/identity.json index 165b8f4..15431ce 100644 --- a/knowledge/ports/livorno/identity.json +++ b/knowledge/ports/livorno/identity.json @@ -8,35 +8,22 @@ "latitude": 43.551, "longitude": 10.301 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Porto Mediceo & Molo Italia", - "berths": [ - "Livorno Berth 1", - "Livorno Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Livorno.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/london/identity.json b/knowledge/ports/london/identity.json index e55d84e..00c1a04 100644 --- a/knowledge/ports/london/identity.json +++ b/knowledge/ports/london/identity.json @@ -8,34 +8,22 @@ "latitude": 51.46, "longitude": 0.36 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "London International Cruise Terminal Tilbury", - "berths": [ - "London Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in London Tilbury / Greenwich Cruise Terminal.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/los-angeles/identity.json b/knowledge/ports/los-angeles/identity.json index 6fcbab7..1b3f93f 100644 --- a/knowledge/ports/los-angeles/identity.json +++ b/knowledge/ports/los-angeles/identity.json @@ -8,34 +8,22 @@ "latitude": 33.743, "longitude": -118.267 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Berths 91-93 San Pedro", - "berths": [ - "Los-Angeles Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Los Angeles.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/malaga/identity.json b/knowledge/ports/malaga/identity.json index 93443c4..0fabc63 100644 --- a/knowledge/ports/malaga/identity.json +++ b/knowledge/ports/malaga/identity.json @@ -8,35 +8,22 @@ "latitude": 36.7167, "longitude": -4.4167 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle de Levante Terminals A & B", - "berths": [ - "Malaga Berth 1", - "Malaga Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Malaga.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/marseille/identity.json b/knowledge/ports/marseille/identity.json index dbf678c..a480b3c 100644 --- a/knowledge/ports/marseille/identity.json +++ b/knowledge/ports/marseille/identity.json @@ -8,35 +8,22 @@ "latitude": 43.3414, "longitude": 5.3468 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Marseille Provence Cruise Terminal (Môle Léon Gourret)", - "berths": [ - "Marseille Berth 1", - "Marseille Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Marseille Fos.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/mazatlan/identity.json b/knowledge/ports/mazatlan/identity.json index 1c98cf9..9e23371 100644 --- a/knowledge/ports/mazatlan/identity.json +++ b/knowledge/ports/mazatlan/identity.json @@ -8,34 +8,22 @@ "latitude": 23.2, "longitude": -106.415 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Mazatlán Cruise Terminal (Blue Line Walk)", - "berths": [ - "Mazatlan Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "MXN", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Mazatlán.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/messina/identity.json b/knowledge/ports/messina/identity.json index 93d609c..fdb41e2 100644 --- a/knowledge/ports/messina/identity.json +++ b/knowledge/ports/messina/identity.json @@ -8,35 +8,22 @@ "latitude": 38.19, "longitude": 15.56 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Banchina Colapesce & Molo Marconi", - "berths": [ - "Messina Berth 1", - "Messina Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Messina.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/miami/identity.json b/knowledge/ports/miami/identity.json index 2169bcc..7d29430 100644 --- a/knowledge/ports/miami/identity.json +++ b/knowledge/ports/miami/identity.json @@ -8,35 +8,22 @@ "latitude": 25.7743, "longitude": -80.1706 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Terminals A, AA, B, C, D, E, F, G, J, V", - "berths": [ - "Miami Berth 1", - "Miami Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in PortMiami.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/monaco/identity.json b/knowledge/ports/monaco/identity.json index fd05da4..57deecd 100644 --- a/knowledge/ports/monaco/identity.json +++ b/knowledge/ports/monaco/identity.json @@ -8,35 +8,22 @@ "latitude": 43.735, "longitude": 7.423 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Nouvelle Digue Flottante (Floating Pier)", - "berths": [ - "Monaco Berth 1", - "Monaco Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port Hercules.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/mykonos/identity.json b/knowledge/ports/mykonos/identity.json index 3ab31f2..5b4482b 100644 --- a/knowledge/ports/mykonos/identity.json +++ b/knowledge/ports/mykonos/identity.json @@ -8,35 +8,22 @@ "latitude": 37.46, "longitude": 25.325 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "New Port of Tourlos & SeaBus Transfer", - "berths": [ - "Mykonos Berth 1", - "Mykonos Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Mykonos.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/naples/identity.json b/knowledge/ports/naples/identity.json index 68e18f7..3d9129f 100644 --- a/knowledge/ports/naples/identity.json +++ b/knowledge/ports/naples/identity.json @@ -8,35 +8,22 @@ "latitude": 40.838, "longitude": 14.258 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Stazione Marittima di Napoli (Molo Angioino)", - "berths": [ - "Naples Berth 1", - "Naples Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Naples.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/nassau/identity.json b/knowledge/ports/nassau/identity.json index 2ba4e68..20dd44b 100644 --- a/knowledge/ports/nassau/identity.json +++ b/knowledge/ports/nassau/identity.json @@ -8,35 +8,22 @@ "latitude": 25.08, "longitude": -77.34 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Prince George Wharf", - "berths": [ - "Nassau Berth 1", - "Nassau Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Nassau Cruise Port.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/new-orleans/identity.json b/knowledge/ports/new-orleans/identity.json index 7ecae09..cb6cd15 100644 --- a/knowledge/ports/new-orleans/identity.json +++ b/knowledge/ports/new-orleans/identity.json @@ -8,35 +8,22 @@ "latitude": 29.938, "longitude": -90.06 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Erato Street & Julia Street Cruise Terminals", - "berths": [ - "New-Orleans Berth 1", - "New-Orleans Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of New Orleans.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/new-york/identity.json b/knowledge/ports/new-york/identity.json index 9f3c647..017e5af 100644 --- a/knowledge/ports/new-york/identity.json +++ b/knowledge/ports/new-york/identity.json @@ -8,35 +8,22 @@ "latitude": 40.765, "longitude": -73.998 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Manhattan (Piers 88/90) & Brooklyn (Pier 12)", - "berths": [ - "New-York Berth 1", - "New-York Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of New York.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/nice-villefranche/identity.json b/knowledge/ports/nice-villefranche/identity.json index e2cf5ab..923bbf0 100644 --- a/knowledge/ports/nice-villefranche/identity.json +++ b/knowledge/ports/nice-villefranche/identity.json @@ -8,35 +8,22 @@ "latitude": 43.7, "longitude": 7.31 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Rade de Villefranche Tender Anchorage", - "berths": [ - "Nice-Villefranche Berth 1", - "Nice-Villefranche Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Villefranche-sur-Mer / Nice.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/ocho-rios/identity.json b/knowledge/ports/ocho-rios/identity.json index 19e92c8..fa817f4 100644 --- a/knowledge/ports/ocho-rios/identity.json +++ b/knowledge/ports/ocho-rios/identity.json @@ -8,34 +8,22 @@ "latitude": 18.41, "longitude": -77.108 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Turtle Beach & James Bond Pier", - "berths": [ - "Ocho-Rios Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "999" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Ocho Rios.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/oranjestad/identity.json b/knowledge/ports/oranjestad/identity.json index 9c26df4..7df9dfb 100644 --- a/knowledge/ports/oranjestad/identity.json +++ b/knowledge/ports/oranjestad/identity.json @@ -8,35 +8,22 @@ "latitude": 12.52, "longitude": -70.04 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Aruba Ports Authority Cruise Terminal", - "berths": [ - "Oranjestad Berth 1", - "Oranjestad Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Oranjestad.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/oslo/identity.json b/knowledge/ports/oslo/identity.json index 2bb4a2e..1202261 100644 --- a/knowledge/ports/oslo/identity.json +++ b/knowledge/ports/oslo/identity.json @@ -8,35 +8,22 @@ "latitude": 59.905, "longitude": 10.74 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Søndre Akershuskai (Below Akershus Fortress)", - "berths": [ - "Oslo Berth 1", - "Oslo Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Oslo.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/palermo/identity.json b/knowledge/ports/palermo/identity.json index fdfc7a9..da05e3b 100644 --- a/knowledge/ports/palermo/identity.json +++ b/knowledge/ports/palermo/identity.json @@ -8,35 +8,22 @@ "latitude": 38.125, "longitude": 13.365 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Molo Vittorio Veneto Terminal", - "berths": [ - "Palermo Berth 1", - "Palermo Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Palermo.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/palma-de-mallorca/identity.json b/knowledge/ports/palma-de-mallorca/identity.json index c423e4c..1e7dce3 100644 --- a/knowledge/ports/palma-de-mallorca/identity.json +++ b/knowledge/ports/palma-de-mallorca/identity.json @@ -8,35 +8,22 @@ "latitude": 39.5539, "longitude": 2.6289 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Estación Marítima (Muelle de Poniente)", - "berths": [ - "Palma-De-Mallorca Berth 1", - "Palma-De-Mallorca Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Palma de Mallorca.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/passau/identity.json b/knowledge/ports/passau/identity.json index d109837..b691fd0 100644 --- a/knowledge/ports/passau/identity.json +++ b/knowledge/ports/passau/identity.json @@ -8,35 +8,22 @@ "latitude": 48.575, "longitude": 13.465 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Passau Lindau & Racklau Danube Berths", - "berths": [ - "Passau Berth 1", - "Passau Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Passau.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/pinhao/identity.json b/knowledge/ports/pinhao/identity.json index f5abf4a..b92f4eb 100644 --- a/knowledge/ports/pinhao/identity.json +++ b/knowledge/ports/pinhao/identity.json @@ -8,35 +8,22 @@ "latitude": 41.19, "longitude": -7.545 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Pinhão Pier (Vintage Port Quinta Heart)", - "berths": [ - "Pinhao Berth 1", - "Pinhao Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Pinhão River Pier.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/piraeus/identity.json b/knowledge/ports/piraeus/identity.json index 417fe37..861de12 100644 --- a/knowledge/ports/piraeus/identity.json +++ b/knowledge/ports/piraeus/identity.json @@ -8,35 +8,22 @@ "latitude": 37.94, "longitude": 23.63 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Piraeus Cruise Terminal (MIAOULIS Terminal A/B/C)", - "berths": [ - "Piraeus Berth 1", - "Piraeus Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Piraeus.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/port-canaveral/identity.json b/knowledge/ports/port-canaveral/identity.json index 3fe484b..6cdf706 100644 --- a/knowledge/ports/port-canaveral/identity.json +++ b/knowledge/ports/port-canaveral/identity.json @@ -8,35 +8,22 @@ "latitude": 28.412, "longitude": -80.608 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cruise Terminals 1, 3, 5, 6, 8, 10", - "berths": [ - "Port-Canaveral Berth 1", - "Port-Canaveral Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port Canaveral.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/port-everglades/identity.json b/knowledge/ports/port-everglades/identity.json index 0af5b9b..d6c22bd 100644 --- a/knowledge/ports/port-everglades/identity.json +++ b/knowledge/ports/port-everglades/identity.json @@ -8,34 +8,22 @@ "latitude": 26.0864, "longitude": -80.1189 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Terminal 25 & 18", - "berths": [ - "Port-Everglades Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port Everglades.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/porto/identity.json b/knowledge/ports/porto/identity.json index c3dcf46..7cc8d3e 100644 --- a/knowledge/ports/porto/identity.json +++ b/knowledge/ports/porto/identity.json @@ -8,35 +8,22 @@ "latitude": 41.1403, "longitude": -8.6133 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cais da Ribeira & Vila Nova de Gaia", - "berths": [ - "Porto Berth 1", - "Porto Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Porto / Douro River.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/puerto-vallarta/identity.json b/knowledge/ports/puerto-vallarta/identity.json index fe350a2..c6c9700 100644 --- a/knowledge/ports/puerto-vallarta/identity.json +++ b/knowledge/ports/puerto-vallarta/identity.json @@ -8,34 +8,22 @@ "latitude": 20.655, "longitude": -105.24 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Puerto Mágico Cruise Terminal", - "berths": [ - "Puerto-Vallarta Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "MXN", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Puerto Vallarta.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/regua/identity.json b/knowledge/ports/regua/identity.json index de31729..17162c9 100644 --- a/knowledge/ports/regua/identity.json +++ b/knowledge/ports/regua/identity.json @@ -8,35 +8,22 @@ "latitude": 41.16, "longitude": -7.785 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cais da Régua (Douro Wine Museum)", - "berths": [ - "Regua Berth 1", - "Regua Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Peso da Régua.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/reykjavik/identity.json b/knowledge/ports/reykjavik/identity.json index 136e83f..ed6a623 100644 --- a/knowledge/ports/reykjavik/identity.json +++ b/knowledge/ports/reykjavik/identity.json @@ -8,35 +8,22 @@ "latitude": 64.15, "longitude": -21.93 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Skarfabakki & Miðbakki Harbour", - "berths": [ - "Reykjavik Berth 1", - "Reykjavik Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Reykjavik.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/rhodes/identity.json b/knowledge/ports/rhodes/identity.json index 8c1b537..2ff373b 100644 --- a/knowledge/ports/rhodes/identity.json +++ b/knowledge/ports/rhodes/identity.json @@ -8,35 +8,22 @@ "latitude": 36.444, "longitude": 28.232 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Rhodes Acandia & Tourist Port (Medieval Walls)", - "berths": [ - "Rhodes Berth 1", - "Rhodes Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Rhodes.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/riga/identity.json b/knowledge/ports/riga/identity.json index faebb09..7e00000 100644 --- a/knowledge/ports/riga/identity.json +++ b/knowledge/ports/riga/identity.json @@ -8,35 +8,22 @@ "latitude": 56.958, "longitude": 24.095 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Riga Passenger Terminal (Vanšu Bridge)", - "berths": [ - "Riga Berth 1", - "Riga Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Riga.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/roatan/identity.json b/knowledge/ports/roatan/identity.json index 05b4485..31a7689 100644 --- a/knowledge/ports/roatan/identity.json +++ b/knowledge/ports/roatan/identity.json @@ -8,35 +8,22 @@ "latitude": 16.315, "longitude": -86.54 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Port of Roatan & Mahogany Bay Carnival Pier", - "berths": [ - "Roatan Berth 1", - "Roatan Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Roatan.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/rotterdam/identity.json b/knowledge/ports/rotterdam/identity.json index c096e11..9ada8c3 100644 --- a/knowledge/ports/rotterdam/identity.json +++ b/knowledge/ports/rotterdam/identity.json @@ -8,35 +8,22 @@ "latitude": 51.905, "longitude": 4.485 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Wilhelminakade (Historic Holland America Line HQ)", - "berths": [ - "Rotterdam Berth 1", - "Rotterdam Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Cruise Port Rotterdam.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/san-juan/identity.json b/knowledge/ports/san-juan/identity.json index 46f7a88..82d1dfc 100644 --- a/knowledge/ports/san-juan/identity.json +++ b/knowledge/ports/san-juan/identity.json @@ -8,35 +8,22 @@ "latitude": 18.462, "longitude": -66.115 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Old San Juan Piers 1-4 & Pan American Pier", - "berths": [ - "San-Juan Berth 1", - "San-Juan Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of San Juan.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/santa-cruz-de-tenerife/identity.json b/knowledge/ports/santa-cruz-de-tenerife/identity.json index 818e0b1..f1a5ef5 100644 --- a/knowledge/ports/santa-cruz-de-tenerife/identity.json +++ b/knowledge/ports/santa-cruz-de-tenerife/identity.json @@ -8,35 +8,22 @@ "latitude": 28.468, "longitude": -16.242 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle de Ribera Cruise Terminal", - "berths": [ - "Santa-Cruz-De-Tenerife Berth 1", - "Santa-Cruz-De-Tenerife Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Santa Cruz de Tenerife.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/santorini/identity.json b/knowledge/ports/santorini/identity.json index 0f75f7d..9d1902a 100644 --- a/knowledge/ports/santorini/identity.json +++ b/knowledge/ports/santorini/identity.json @@ -8,35 +8,22 @@ "latitude": 36.4167, "longitude": 25.4333 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Old Port Skala (Tender Anchorage & Cable Car)", - "berths": [ - "Santorini Berth 1", - "Santorini Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Santorini.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/seattle/identity.json b/knowledge/ports/seattle/identity.json index 31df452..09f5656 100644 --- a/knowledge/ports/seattle/identity.json +++ b/knowledge/ports/seattle/identity.json @@ -8,35 +8,22 @@ "latitude": 47.612, "longitude": -122.355 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Bell Street Pier 66 & Smith Cove Pier 91", - "berths": [ - "Seattle Berth 1", - "Seattle Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Seattle.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/shanghai/identity.json b/knowledge/ports/shanghai/identity.json index 8a3ef49..eb6f544 100644 --- a/knowledge/ports/shanghai/identity.json +++ b/knowledge/ports/shanghai/identity.json @@ -8,34 +8,22 @@ "latitude": 31.396, "longitude": 121.505 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Baoshan Wusongkou Terminal", - "berths": [ - "Shanghai Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "999" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Shanghai Wusongkou International Cruise Terminal.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/singapore/identity.json b/knowledge/ports/singapore/identity.json index 548ff2f..3dece3f 100644 --- a/knowledge/ports/singapore/identity.json +++ b/knowledge/ports/singapore/identity.json @@ -8,34 +8,22 @@ "latitude": 1.268, "longitude": 103.861 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Marina Bay Cruise Centre Singapore", - "berths": [ - "Singapore Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "SGD", - "card_acceptance_pct": 98, - "emergency_phone": "999" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Singapore Marina Bay Cruise Centre.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/skagway/identity.json b/knowledge/ports/skagway/identity.json index ca2b25e..bdf8e00 100644 --- a/knowledge/ports/skagway/identity.json +++ b/knowledge/ports/skagway/identity.json @@ -8,35 +8,22 @@ "latitude": 59.452, "longitude": -135.32 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Ore Dock, Broadway Dock, Railroad Dock", - "berths": [ - "Skagway Berth 1", - "Skagway Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Skagway.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/southampton/identity.json b/knowledge/ports/southampton/identity.json index f1420f8..890eafb 100644 --- a/knowledge/ports/southampton/identity.json +++ b/knowledge/ports/southampton/identity.json @@ -8,35 +8,22 @@ "latitude": 50.895, "longitude": -1.405 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Horizon, Mayflower, Ocean & City Cruise Terminals", - "berths": [ - "Southampton Berth 1", - "Southampton Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "GBP", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Southampton.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/split/identity.json b/knowledge/ports/split/identity.json index 9cecfbf..12abbd9 100644 --- a/knowledge/ports/split/identity.json +++ b/knowledge/ports/split/identity.json @@ -8,35 +8,22 @@ "latitude": 43.505, "longitude": 16.442 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Gat Sv. Duje & Gat Sv. Petra (Diocletian Palace Gate)", - "berths": [ - "Split Berth 1", - "Split Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Split.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/st-maarten/identity.json b/knowledge/ports/st-maarten/identity.json index 533c1e8..d808bbf 100644 --- a/knowledge/ports/st-maarten/identity.json +++ b/knowledge/ports/st-maarten/identity.json @@ -8,35 +8,22 @@ "latitude": 18.015, "longitude": -63.045 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Dr. A.C. Wathey Cruise Facility", - "berths": [ - "St-Maarten Berth 1", - "St-Maarten Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of St. Maarten.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/st-thomas/identity.json b/knowledge/ports/st-thomas/identity.json index b2612f9..266c5cd 100644 --- a/knowledge/ports/st-thomas/identity.json +++ b/knowledge/ports/st-thomas/identity.json @@ -8,35 +8,22 @@ "latitude": 18.335, "longitude": -64.92 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "West Indian Company Dock (Havensight) & Crown Bay", - "berths": [ - "St-Thomas Berth 1", - "St-Thomas Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of St. Thomas.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/stavanger/identity.json b/knowledge/ports/stavanger/identity.json index 1c7bff9..fc3ac76 100644 --- a/knowledge/ports/stavanger/identity.json +++ b/knowledge/ports/stavanger/identity.json @@ -8,35 +8,22 @@ "latitude": 58.972, "longitude": 5.731 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Strandkaien & Skagenkaien (Old Stavanger)", - "berths": [ - "Stavanger Berth 1", - "Stavanger Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Stavanger.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/stockholm/identity.json b/knowledge/ports/stockholm/identity.json index b6109bd..d9b6a90 100644 --- a/knowledge/ports/stockholm/identity.json +++ b/knowledge/ports/stockholm/identity.json @@ -8,35 +8,22 @@ "latitude": 59.338, "longitude": 18.115 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Frihamnen, Värtahamnen & Stadsgården", - "berths": [ - "Stockholm Berth 1", - "Stockholm Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Stockholm.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/strasbourg/identity.json b/knowledge/ports/strasbourg/identity.json index 868927b..cf2a114 100644 --- a/knowledge/ports/strasbourg/identity.json +++ b/knowledge/ports/strasbourg/identity.json @@ -8,35 +8,22 @@ "latitude": 48.575, "longitude": 7.795 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Parc du Rhin & Rue du Havre River Pier", - "berths": [ - "Strasbourg Berth 1", - "Strasbourg Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Strasbourg.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/sydney/identity.json b/knowledge/ports/sydney/identity.json index 3ebb681..699c74f 100644 --- a/knowledge/ports/sydney/identity.json +++ b/knowledge/ports/sydney/identity.json @@ -8,34 +8,22 @@ "latitude": -33.858, "longitude": 151.21 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Circular Quay OPT (Direct Opera House View)", - "berths": [ - "Sydney Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "AUD", - "card_acceptance_pct": 98, - "emergency_phone": "999" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Sydney.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/tallinn/identity.json b/knowledge/ports/tallinn/identity.json index a67f043..7711608 100644 --- a/knowledge/ports/tallinn/identity.json +++ b/knowledge/ports/tallinn/identity.json @@ -8,35 +8,22 @@ "latitude": 59.445, "longitude": 24.76 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Old City Harbour Cruise Promenade", - "berths": [ - "Tallinn Berth 1", - "Tallinn Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Tallinn.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/tampa/identity.json b/knowledge/ports/tampa/identity.json index eae637f..66d24d2 100644 --- a/knowledge/ports/tampa/identity.json +++ b/knowledge/ports/tampa/identity.json @@ -8,35 +8,22 @@ "latitude": 27.942, "longitude": -82.448 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Cruise Terminals 2, 3, 6", - "berths": [ - "Tampa Berth 1", - "Tampa Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "USD", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port Tampa Bay.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/trieste/identity.json b/knowledge/ports/trieste/identity.json index 93e3ac9..d2692fe 100644 --- a/knowledge/ports/trieste/identity.json +++ b/knowledge/ports/trieste/identity.json @@ -8,34 +8,22 @@ "latitude": 45.65, "longitude": 13.765 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Stazione Marittima di Trieste", - "berths": [ - "Trieste Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Trieste.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/tromso/identity.json b/knowledge/ports/tromso/identity.json index 87367c6..8cf4eed 100644 --- a/knowledge/ports/tromso/identity.json +++ b/knowledge/ports/tromso/identity.json @@ -8,35 +8,22 @@ "latitude": 69.652, "longitude": 18.96 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Breivika Cruise Port & Prostneset", - "berths": [ - "Tromso Berth 1", - "Tromso Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "NOK", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Tromsø.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/ushuaia/identity.json b/knowledge/ports/ushuaia/identity.json index ef1e962..ad349f0 100644 --- a/knowledge/ports/ushuaia/identity.json +++ b/knowledge/ports/ushuaia/identity.json @@ -8,34 +8,22 @@ "latitude": -54.81, "longitude": -68.3 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle Comercial Ushuaia", - "berths": [ - "Ushuaia Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Ushuaia.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/valencia/identity.json b/knowledge/ports/valencia/identity.json index 8ac7873..5bf5299 100644 --- a/knowledge/ports/valencia/identity.json +++ b/knowledge/ports/valencia/identity.json @@ -8,35 +8,22 @@ "latitude": 39.456, "longitude": -0.325 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Muelle Transversales & Poniente", - "berths": [ - "Valencia Berth 1", - "Valencia Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Valencia.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/valletta/identity.json b/knowledge/ports/valletta/identity.json index 3dd45ab..718e3dd 100644 --- a/knowledge/ports/valletta/identity.json +++ b/knowledge/ports/valletta/identity.json @@ -8,35 +8,22 @@ "latitude": 35.89, "longitude": 14.51 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Valletta Waterfront (Pinto Wharf)", - "berths": [ - "Valletta Berth 1", - "Valletta Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Grand Harbour.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/vancouver/identity.json b/knowledge/ports/vancouver/identity.json index 7f13da9..d84fc74 100644 --- a/knowledge/ports/vancouver/identity.json +++ b/knowledge/ports/vancouver/identity.json @@ -8,35 +8,22 @@ "latitude": 49.288, "longitude": -123.111 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Canada Place Cruise Ship Terminal", - "berths": [ - "Vancouver Berth 1", - "Vancouver Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Vancouver.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/venice-ravenna/identity.json b/knowledge/ports/venice-ravenna/identity.json index 1dd52c6..1180ca9 100644 --- a/knowledge/ports/venice-ravenna/identity.json +++ b/knowledge/ports/venice-ravenna/identity.json @@ -8,35 +8,22 @@ "latitude": 44.49, "longitude": 12.28 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Porto Corsini Terminal Crociere", - "berths": [ - "Venice-Ravenna Berth 1", - "Venice-Ravenna Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Ravenna.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/venice-trieste/identity.json b/knowledge/ports/venice-trieste/identity.json index e81cfb0..c8e4d49 100644 --- a/knowledge/ports/venice-trieste/identity.json +++ b/knowledge/ports/venice-trieste/identity.json @@ -8,35 +8,22 @@ "latitude": 45.65, "longitude": 13.765 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Trieste Maritime Terminal (Molo Bersaglieri)", - "berths": [ - "Venice-Trieste Berth 1", - "Venice-Trieste Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Trieste.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/victoria/identity.json b/knowledge/ports/victoria/identity.json index 58e808d..f3e23a2 100644 --- a/knowledge/ports/victoria/identity.json +++ b/knowledge/ports/victoria/identity.json @@ -8,34 +8,22 @@ "latitude": 48.415, "longitude": -123.385 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Ogden Point Terminal (Piers A & B)", - "berths": [ - "Victoria Pier 1" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "911" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Verify pier location in Port of Victoria.", - "Keep ship ID card securely zipped." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/vienna/identity.json b/knowledge/ports/vienna/identity.json index ee314ae..6191f2b 100644 --- a/knowledge/ports/vienna/identity.json +++ b/knowledge/ports/vienna/identity.json @@ -8,35 +8,22 @@ "latitude": 48.225, "longitude": 16.405 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Reichsbrücke & Handelskai River Piers", - "berths": [ - "Vienna Berth 1", - "Vienna Berth 2" - ], - "gangway_deck_default": 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Vienna.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/warnemunde-rostock/identity.json b/knowledge/ports/warnemunde-rostock/identity.json index d6a53d7..fcec8dc 100644 --- a/knowledge/ports/warnemunde-rostock/identity.json +++ b/knowledge/ports/warnemunde-rostock/identity.json @@ -8,35 +8,22 @@ "latitude": 54.175, "longitude": 12.09 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Warnemünde Cruise Center P7/P8", - "berths": [ - "Warnemunde-Rostock Berth 1", - "Warnemunde-Rostock Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Warnemünde.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/willemstad/identity.json b/knowledge/ports/willemstad/identity.json index 4e2dfcc..e7e9baa 100644 --- a/knowledge/ports/willemstad/identity.json +++ b/knowledge/ports/willemstad/identity.json @@ -8,35 +8,22 @@ "latitude": 12.108, "longitude": -68.938 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Mega Pier 1 & 2 (Tula/Jackie) & Mathey Wharf", - "berths": [ - "Willemstad Berth 1", - "Willemstad Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Willemstad.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/knowledge/ports/zeebrugge/identity.json b/knowledge/ports/zeebrugge/identity.json index 26fcace..5037701 100644 --- a/knowledge/ports/zeebrugge/identity.json +++ b/knowledge/ports/zeebrugge/identity.json @@ -8,35 +8,22 @@ "latitude": 51.335, "longitude": 3.205 }, - "timezone": "UTC", + "timezone": null, "terminals": [ { "name": "Zweedse Kaai Cruise Terminal", - "berths": [ - "Zeebrugge Berth 1", - "Zeebrugge Berth 2" - ], - "gangway_deck_default": 5, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": true + "berths": [], + "gangway_deck_default": null, + "distance_to_city_center_m": null, + "walking_time_min": null, + "step_free_access": null } ], "logistics": { - "currency": "EUR", - "card_acceptance_pct": 98, - "emergency_phone": "112" + "currency": null, + "card_acceptance_pct": null, + "emergency_phone": null }, - "negative_intelligence": [ - "Check terminal berth assignment upon morning arrival in Port of Zeebrugge.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - { - "field": "all", - "source_id": "src:official-port-authority", - "trust_level": "OFFICIAL", - "retrieved_at": "2026-08-16T12:00:00Z" - } - ] + "negative_intelligence": [], + "sources": [] } \ No newline at end of file diff --git a/tests/compiler_sandbox.py b/tests/compiler_sandbox.py new file mode 100644 index 0000000..51ed275 --- /dev/null +++ b/tests/compiler_sandbox.py @@ -0,0 +1,82 @@ +"""A compiler root that does not write into the repository. + +`KnowledgeDBCompiler.compile()` writes `cruise_intelligence_db.json` and +`cruise_knowledge_graph.json` into `/data` on every call, and the +compiler exposes no output-path option. Any test constructing it with the +repository root therefore rewrites two tracked files as a side effect. + +That matters beyond tidiness. Those artifacts are already known to be stale on +`develop` — regeneration produces a large diff unrelated to any current change +— so a test suite that silently rewrites them destroys the evidence of that +drift and makes `git status` after a test run meaningless. + +`sandbox_root()` returns a temporary directory that exposes the real corpus at +`knowledge`. The compiler reads the real data and writes its artifacts into the +sandbox. Nothing is restored afterwards, because nothing is modified: restoring +tracked files after mutating them is still mutation, and would mask exactly the +drift this helper protects. + +A symlink is the cheap way to expose the corpus, but it is not portable: on +Windows `os.symlink` needs SeCreateSymbolicLinkPrivilege, which an ordinary +account without Developer Mode does not hold, and the call fails with +WinError 1314. Copying is the fallback rather than a skip, because the point of +these tests is to exercise the real corpus — skipping them on the platform this +repository is developed on would remove the coverage exactly where a regression +would land first. The corpus is ~2 MB across ~450 files, so the copy is cheap. + +Either way the compiler only reads the corpus, so the repository copy is +untouched in both modes. +""" + +from __future__ import annotations + +import pathlib +import shutil +import tempfile + +REPO_ROOT = pathlib.Path(__file__).resolve().parents[1] + + +def expose_knowledge(root: pathlib.Path) -> str: + """Make the real corpus readable at ``/knowledge``. + + Returns the mechanism used, ``"symlink"`` or ``"copy"``, so a caller can + assert on it if it cares. `FileExistsError` is deliberately not caught: it + means the caller passed a root that is already populated, which is a bug in + the test rather than a platform limitation, and copying over it would hide + that. + """ + target = root / "knowledge" + source = REPO_ROOT / "knowledge" + try: + target.symlink_to(source, target_is_directory=True) + return "symlink" + except FileExistsError: + raise + except (OSError, NotImplementedError): + # No symlink privilege (or no symlink support at all). Copy instead. + shutil.copytree(source, target) + return "copy" + + +def sandbox_root(cleanup_registry=None) -> str: + """Return a compiler `root_dir` whose writes land outside the repository. + + `cleanup_registry`, if given, must have an `append` method; the + `TemporaryDirectory` handle is appended to it so the caller can keep it + alive for as long as the sandbox is needed. Without it the directory is + removed when the handle is garbage collected, which for a `setUpClass` + caller may be sooner than intended. + """ + handle = tempfile.TemporaryDirectory(prefix="timonelo-compile-") + root = pathlib.Path(handle.name) + expose_knowledge(root) + if cleanup_registry is not None: + cleanup_registry.append(handle) + else: + # Attach to the returned path's owner so it outlives this call. + sandbox_root._handles.append(handle) # type: ignore[attr-defined] + return str(root) + + +sandbox_root._handles = [] # type: ignore[attr-defined] diff --git a/tests/test_cruise_intelligence_db.py b/tests/test_cruise_intelligence_db.py index 2e10fb3..418f78e 100644 --- a/tests/test_cruise_intelligence_db.py +++ b/tests/test_cruise_intelligence_db.py @@ -7,12 +7,16 @@ sys.path.insert(0, REPO_ROOT) from src.timonelo.database.compiler import KnowledgeDBCompiler + +from tests.compiler_sandbox import sandbox_root from src.timonelo.database.graph import RelationType class TestCruiseIntelligenceDatabase(unittest.TestCase): def setUp(self): - self.compiler = KnowledgeDBCompiler(REPO_ROOT) + # Sandboxed root: compile() writes generated artifacts, and a test + # must not rewrite tracked files under data/. See tests/compiler_sandbox.py. + self.compiler = KnowledgeDBCompiler(sandbox_root()) self.db = self.compiler.compile() self.graph = self.compiler.knowledge_graph diff --git a/tests/test_frontend_bridge_trust_boundary.py b/tests/test_frontend_bridge_trust_boundary.py new file mode 100644 index 0000000..9bebffd --- /dev/null +++ b/tests/test_frontend_bridge_trust_boundary.py @@ -0,0 +1,226 @@ +"""Trust-boundary invariants for the frontend bridge (audit U-1). + +The bridge exists to carry canonical knowledge to the passenger surface. The +failure it exhibited was not carrying anything: for every field the knowledge +layer could not supply, it substituted a plausible literal and shipped that +instead -- `walkingTimeMin: 10`, `cardAcceptancePct: 98`, a `stepFreeAccess` +assertion for all 119 ports, and an `officialSource` naming Timonelo's own +domain as the port authority under `trustLevel: "OFFICIAL"`. + +That is worse than a gap. A missing value invites checking; a confident wrong +value suppresses it. And because the substitution happened downstream of the +knowledge layer, no amount of governance applied to `knowledge/ports/` could +reach it -- quarantining the identity layer left the passenger surface +unchanged. + +The rule these tests enforce: **the bridge may propagate provenance, never +originate it.** Checks run against both the generator source and the emitted +artifact, because a leak can be reintroduced in either. +""" + +from __future__ import annotations + +import json +import pathlib +import re + +import pytest + +REPO_ROOT = pathlib.Path(__file__).resolve().parents[1] +BRIDGE = REPO_ROOT / "tools" / "generate_frontend_bridge.py" +PORTS_TS = REPO_ROOT / "frontend" / "src" / "generated" / "ports.ts" + +#: Timonelo is not a port authority. Emitting its own domain as the source URL +#: for a port fact is self-attestation with the shape of evidence. +SELF_ATTESTATION_HOSTS = ("timonelo.com", "www.timonelo.com") + +#: Genoa's code, previously the `.get("un_locode", ...)` fallback. Any port +#: without a code silently became Genoa. +LOCODE_FALLBACK = "ITGOA" + + +def _bridge_code() -> str: + """Generator source with comments stripped. + + The comments document the removed literals by name, so matching against + the raw file would flag the explanation as the offence. + """ + return "\n".join( + line + for line in BRIDGE.read_text(encoding="utf-8").splitlines() + if not line.lstrip().startswith("#") + ) + + +@pytest.fixture(scope="module") +def emitted_ports() -> list[dict]: + """The `PORTS_REGISTRY` array parsed out of the generated TypeScript.""" + text = PORTS_TS.read_text(encoding="utf-8") + marker = "PORTS_REGISTRY: PortData[] = " + start = text.index(marker) + len(marker) + end = text.rindex("];") + 1 + records = json.loads(text[start:end]) + assert records, "generated ports.ts contains no port records" + return records + + +# -------------------------------------------------------------------------- +# Generator source +# -------------------------------------------------------------------------- + +def test_bridge_does_not_self_attest_as_authority(): + code = _bridge_code() + for host in SELF_ATTESTATION_HOSTS: + assert host not in code, ( + f"bridge emits {host!r} as a source URL. Timonelo is not a port " + "authority; provenance is propagated from the knowledge layer or " + "omitted (audit U-1)." + ) + + +def test_bridge_does_not_originate_trust_levels(): + """`OFFICIAL` may be read from upstream, never written as a literal.""" + code = _bridge_code() + offenders = [ + line.strip() + for line in code.splitlines() + if re.search(r"""['"]OFFICIAL['"]""", line) + and "trust_level" not in line # reading the upstream key is fine + ] + assert not offenders, ( + f"bridge writes a literal trust level: {offenders[:3]}. Trust is a " + "property of evidence, not a presentation default (audit U-1)." + ) + + +def test_bridge_has_no_locode_fallback(): + code = _bridge_code() + assert LOCODE_FALLBACK not in code, ( + f"bridge still references {LOCODE_FALLBACK!r}. A missing UN/LOCODE " + "must stay missing rather than relabelling the port as Genoa." + ) + + +@pytest.mark.parametrize( + "literal", + ['"walkingTimeMin": 10', '"cardAcceptancePct": 98', + '"distanceToCenterM": 500', '"gangwayDeckDefault": 5', + '"stepFreeAccess": True', '"berths": ["Berth 1"'], +) +def test_bridge_emits_no_hardcoded_passenger_values(literal): + assert literal not in _bridge_code(), ( + f"bridge hardcodes {literal!r}. Passenger-facing values come from the " + "knowledge layer or are null (audit U-1)." + ) + + +# -------------------------------------------------------------------------- +# Emitted artifact +# -------------------------------------------------------------------------- + +def test_emitted_ports_contain_no_self_attestation(emitted_ports): + offenders = [ + rec["slug"] + for rec in emitted_ports + if (rec.get("officialSource") or {}).get("url") + and any(h in rec["officialSource"]["url"] for h in SELF_ATTESTATION_HOSTS) + ] + assert not offenders, ( + f"{len(offenders)} emitted port(s) cite Timonelo as the official " + f"source: {offenders[:5]} (audit U-1)." + ) + + +def test_emitted_provenance_is_field_scoped(emitted_ports): + """Any surviving source record must name a field and a source id. + + `field: "all"` was the blanket attestation quarantined by ADR-0006 D2. It + must not reappear by way of the bridge. + """ + offenders = [] + for rec in emitted_ports: + src = rec.get("officialSource") + if src is None: + continue + if not src.get("sourceId") or src.get("field") in (None, "", "all"): + offenders.append((rec["slug"], src)) + assert not offenders, ( + f"{len(offenders)} emitted source record(s) lack field-scoped " + f"provenance: {offenders[:3]} (ADR-0006 D2)." + ) + + +def test_emitted_locode_is_never_a_shared_fallback(emitted_ports): + """No two ports may share a UN/LOCODE via a default. + + Genoa legitimately holds ITGOA. The defect was every codeless port also + holding it, so the check is on duplication rather than on the value. + """ + seen: dict[str, list[str]] = {} + for rec in emitted_ports: + code = rec.get("unLocode") + if code: + seen.setdefault(code, []).append(rec["slug"]) + shared = { + code: slugs + for code, slugs in seen.items() + if len(slugs) > 1 and code == LOCODE_FALLBACK + } + assert not shared, ( + f"the fallback LOCODE is shared across ports: {shared}. A port " + "without a code must emit null (audit U-1)." + ) + + +@pytest.mark.parametrize( + "field", ["walkingTimeMin", "cardAcceptancePct", "distanceToCenterM", + "gangwayDeckDefault", "stepFreeAccess"], +) +def test_emitted_passenger_values_are_not_uniform_constants(emitted_ports, field): + """A single non-null value across every port is a substituted default. + + Stated as uniformity rather than as a banned value, so a genuinely sourced + future value is unaffected: the corpus only fails when every port agrees + and nothing sourced it. + """ + if len(emitted_ports) < 20: + pytest.skip("too few ports for a distribution check") + values = { + rec[field] for rec in emitted_ports if rec.get(field) is not None + } + assert len(values) != 1, ( + f"every emitted port carries {field}={values.pop()!r}. The bridge is " + "substituting a default for a value the knowledge layer does not have " + "(audit U-1)." + ) + + +def test_null_survives_generation(emitted_ports): + """Quarantined fields reach the frontend as null, not as a stand-in. + + The point of the quarantine was that UNKNOWN is publishable. If the bridge + converted null into anything renderable, the quarantine bought nothing. + """ + quarantined = ["walkingTimeMin", "cardAcceptancePct", "gangwayDeckDefault", + "stepFreeAccess", "emergencyPhone", "currency"] + for field in quarantined: + assert all(field in rec for rec in emitted_ports), ( + f"{field} missing from some emitted records; the key must persist " + "so the frontend can distinguish unknown from unmodelled" + ) + nulls = { + field: sum(1 for rec in emitted_ports if rec.get(field) is None) + for field in quarantined + } + assert all(count > 0 for count in nulls.values()), ( + f"no nulls survived generation for some quarantined field: {nulls}. " + "The bridge is filling gaps it should propagate (audit U-1)." + ) + + +def test_emitted_artifact_is_valid_and_complete(emitted_ports): + assert len(emitted_ports) >= 100, ( + f"only {len(emitted_ports)} ports emitted; expected the full corpus" + ) + for rec in emitted_ports: + assert rec.get("slug"), f"emitted record without a slug: {rec}" diff --git a/tests/test_live_fleet_operations.py b/tests/test_live_fleet_operations.py index 8c18cd5..d9692cf 100644 --- a/tests/test_live_fleet_operations.py +++ b/tests/test_live_fleet_operations.py @@ -6,6 +6,8 @@ sys.path.insert(0, REPO_ROOT) from src.timonelo.database.compiler import KnowledgeDBCompiler + +from tests.compiler_sandbox import sandbox_root from src.timonelo.database.operations_schema import ( SeasonalPeriod, PortCallType, @@ -19,7 +21,8 @@ class TestLiveFleetOperations(unittest.TestCase): @classmethod def setUpClass(cls): - compiler = KnowledgeDBCompiler(REPO_ROOT) + # Sandboxed root: see tests/compiler_sandbox.py. + compiler = KnowledgeDBCompiler(sandbox_root()) cls.db = compiler.compile() def test_operations_layer_compiled_entities(self): diff --git a/tests/test_port_identity_quarantine.py b/tests/test_port_identity_quarantine.py new file mode 100644 index 0000000..60f89f3 --- /dev/null +++ b/tests/test_port_identity_quarantine.py @@ -0,0 +1,461 @@ +"""Corpus-wide invariants for the port identity layer (ADR-0006). + +These guard against one specific failure, already realised once on `develop`: +a bulk generator wrote template constants into every `knowledge/ports/*/ +identity.json` and attested them with a single blanket source record +(`field: "all"`, `source_id: "src:official-port-authority"`, +`trust_level: "OFFICIAL"`). Nothing in the repository objected, because every +file was individually well-formed and individually plausible. The defect was +only visible in the DISTRIBUTION across the corpus. + +So these tests are deliberately distribution-based rather than per-file. A +per-file assertion cannot distinguish "10 minutes is the researched walking +time for this port" from "10 minutes is what the template emits"; a +corpus-wide cardinality check can. The rule enforced is: a passenger-facing +numeric may not take one identical value across the entire corpus unless a +field-scoped source attests it. + +`None` is the fail-closed state and is always permitted. The point of the +quarantine is that UNKNOWN is publishable and synthetic precision is not. +""" + +from __future__ import annotations + +import collections +import json +import pathlib + +import pytest + +REPO_ROOT = pathlib.Path(__file__).resolve().parents[1] +PORTS_DIR = REPO_ROOT / "knowledge" / "ports" + +#: Blanket attestation emitted by the bulk generators. `field: "all"` cannot +#: establish provenance for unrelated facts, and this source_id names a +#: category of authority rather than any retrievable document. +BANNED_SOURCE_ID = "src:official-port-authority" + +#: Passenger-facing numerics that were template constants. Each may be None, +#: or may carry a real value attested by a source scoped to that field. +GUARDED_TERMINAL_FIELDS = ( + "walking_time_min", + "distance_to_city_center_m", + "gangway_deck_default", +) +GUARDED_LOGISTICS_FIELDS = ( + "card_acceptance_pct", + "currency", + "emergency_phone", +) + +#: Below this many ports the "one distinct value" signal is meaningless. +MIN_CORPUS_FOR_DISTRIBUTION_CHECK = 20 + + +def _identity_files() -> list[pathlib.Path]: + return sorted(PORTS_DIR.glob("*/identity.json")) + + +def _load(path: pathlib.Path) -> dict: + return json.loads(path.read_text(encoding="utf-8")) + + +@pytest.fixture(scope="module") +def corpus() -> list[tuple[str, dict]]: + files = _identity_files() + assert files, "no port identity files found; check PORTS_DIR" + return [(p.parent.name, _load(p)) for p in files] + + +def _sourced_fields(doc: dict) -> set[str]: + """Field names carrying a field-scoped source record. + + `field: "all"` deliberately contributes nothing: a source covering + everything attests nothing in particular. + """ + out: set[str] = set() + for src in doc.get("sources", []): + field = src.get("field") + if isinstance(field, str) and field != "all": + out.add(field) + elif isinstance(field, list): + out.update(f for f in field if f != "all") + return out + + +def test_json_is_wellformed_and_parses(corpus): + for slug, doc in corpus: + assert isinstance(doc, dict), f"{slug}: identity.json is not an object" + assert doc.get("slug"), f"{slug}: missing slug" + + +def test_no_blanket_official_attestation(corpus): + """`field: "all"` + generic authority id may not attest anything.""" + offenders = [ + slug + for slug, doc in corpus + for src in doc.get("sources", []) + if src.get("field") == "all" and src.get("source_id") == BANNED_SOURCE_ID + ] + assert not offenders, ( + f"{len(offenders)} port(s) re-introduced the blanket attestation " + f"(field='all', source_id='{BANNED_SOURCE_ID}'): {offenders[:10]}. " + "A source covering every field attests none of them; see ADR-0006." + ) + + +def test_no_source_claims_field_all(corpus): + """Any `field: "all"` record is rejected, whatever its source_id. + + Renaming the source_id would otherwise slip the same laundering pattern + past the previous test. + """ + offenders = [ + (slug, src.get("source_id")) + for slug, doc in corpus + for src in doc.get("sources", []) + if src.get("field") == "all" + ] + assert not offenders, ( + f"field='all' provenance found on {len(offenders)} record(s): " + f"{offenders[:10]}. Passenger-facing facts require field-scoped " + "provenance; add an explicit schema exception if one is ever justified." + ) + + +def test_timezone_is_not_uniformly_hardcoded(corpus): + """A single timezone across a global corpus is a generator artefact. + + All-aboard time is computed from this field, so a wrong value strands + passengers. UTC for 119 ports spanning Reykjavik to Sydney is not data. + """ + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + values = collections.Counter( + doc.get("timezone") for _, doc in corpus if doc.get("timezone") is not None + ) + assert len(values) != 1, ( + f"every port with a timezone declares {list(values)[0]!r}. " + "This is template output, not observation. Null it or source it " + "per port (ADR-0006)." + ) + + +@pytest.mark.parametrize("field", GUARDED_TERMINAL_FIELDS) +def test_terminal_numeric_is_not_a_corpus_wide_constant(corpus, field): + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + values = collections.Counter() + for slug, doc in corpus: + if field in _sourced_fields(doc): + continue # individually attested; exempt from the constant check + for term in doc.get("terminals", []): + if term.get(field) is not None: + values[term[field]] += 1 + assert len(values) != 1, ( + f"unsourced {field!r} takes the single value {list(values)[0]!r} across " + f"{sum(values.values())} terminals. Synthetic precision must be null " + "until field-scoped evidence exists (ADR-0006)." + ) + + +@pytest.mark.parametrize("field", GUARDED_LOGISTICS_FIELDS) +def test_logistics_value_is_not_a_corpus_wide_constant(corpus, field): + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + values = collections.Counter( + doc["logistics"][field] + for slug, doc in corpus + if field not in _sourced_fields(doc) + and doc.get("logistics", {}).get(field) is not None + ) + assert len(values) != 1, ( + f"unsourced logistics.{field} takes the single value " + f"{list(values)[0]!r} across {sum(values.values())} ports (ADR-0006)." + ) + + +def test_negative_intelligence_is_not_template_derived(corpus): + """Guidance repeated verbatim across ports is boilerplate, not intelligence. + + Compared on the invariant portion of the string, since the generators + interpolated the port name into an otherwise fixed sentence. + """ + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + counts = collections.Counter( + entry.split(" in ")[0].strip().rstrip(".") + for _, doc in corpus + for entry in doc.get("negative_intelligence", []) + if isinstance(entry, str) + ) + repeated = {k: v for k, v in counts.items() if v > 5} + assert not repeated, ( + f"negative_intelligence entries repeat across many ports: {repeated}. " + "Port-specific guidance cannot be identical corpus-wide (ADR-0006)." + ) + + +def test_unsourced_identity_publishes_no_facts(corpus): + """Fail-closed: no sources means no passenger-facing values. + + Identity data absent evidence may still carry the entity's name and + place. It may not carry claims a traveller could act on. + """ + offenders = [] + for slug, doc in corpus: + if _sourced_fields(doc): + continue + asserted = [ + f for f in GUARDED_LOGISTICS_FIELDS + if doc.get("logistics", {}).get(f) is not None + ] + [ + f for f in GUARDED_TERMINAL_FIELDS + for term in doc.get("terminals", []) + if term.get(f) is not None + ] + if asserted: + offenders.append((slug, sorted(set(asserted)))) + assert not offenders, ( + f"{len(offenders)} port(s) publish passenger-facing values with no " + f"field-scoped source: {offenders[:10]} (ADR-0006)." + ) + + +def test_accessibility_claims_are_not_a_corpus_wide_constant(corpus): + """`step_free_access` may not be uniformly asserted without evidence. + + Separated from the numeric checks because the harm differs in kind. A wrong + walking time costs a passenger ten minutes; a wrong step-free claim sends a + wheelchair user to a gangway they cannot board. The generators asserted + `true` for all 119 ports without a single observation. + + Diversity is not the standard here — a corpus where every *sourced* port + happens to be step-free is legitimate. The standard is that an unsourced + uniform assertion is template output. + """ + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + values = collections.Counter() + for slug, doc in corpus: + if "step_free_access" in _sourced_fields(doc): + continue + for term in doc.get("terminals", []): + if term.get("step_free_access") is not None: + values[term["step_free_access"]] += 1 + assert len(values) != 1, ( + f"unsourced step_free_access is uniformly {list(values)[0]!r} across " + f"{sum(values.values())} terminals. Accessibility claims fail closed: " + "null until observed per terminal (ADR-0006 D5)." + ) + + +def test_accessibility_never_claimed_without_evidence(corpus): + """A positive step-free claim requires field-scoped provenance. + + Stricter than the distribution check and deliberately so. `false` and + `null` need no source — neither sends anyone to an unusable gangway — but + `true` is the claim a passenger acts on, so it carries the burden. + """ + offenders = [ + slug + for slug, doc in corpus + if "step_free_access" not in _sourced_fields(doc) + for term in doc.get("terminals", []) + if term.get("step_free_access") is True + ] + assert not offenders, ( + f"{len(offenders)} terminal(s) claim step_free_access=true with no " + f"field-scoped source: {offenders[:10]} (ADR-0006 D5)." + ) + + +def test_berth_lists_are_not_template_derived(corpus): + """Berth names may not be derived from the port slug. + + Both generators built berths by interpolation — `f"{slug.title()} Berth 1"` + and `f"{slug.title()} Pier 1"`. The tell is that the berth name contains + the slug, which a real berth designation ("Ponte dei Mille", "Berths + 91-93") generally does not. Checked structurally rather than against the + two known templates, so renaming the suffix does not evade it. + """ + offenders = [] + for slug, doc in corpus: + if "berths" in _sourced_fields(doc): + continue + slug_words = slug.replace("-", " ").lower() + for term in doc.get("terminals", []): + for berth in term.get("berths") or []: + if isinstance(berth, str) and slug_words in berth.lower(): + offenders.append((slug, berth)) + assert not offenders, ( + f"{len(offenders)} berth name(s) are interpolated from the port slug: " + f"{offenders[:8]}. Berth designations come from the port authority, " + "not from string formatting (ADR-0006)." + ) + + +def test_berth_counts_are_not_a_corpus_wide_constant(corpus): + """Unsourced ports may not all declare the same number of berths. + + Guards the shape as well as the names: a generator emitting + `["Berth 1", "Berth 2"]` for every port defeats the name check above while + reproducing the same false uniformity. + """ + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + counts = collections.Counter( + len(term.get("berths") or []) + for slug, doc in corpus + if "berths" not in _sourced_fields(doc) + for term in doc.get("terminals", []) + if term.get("berths") + ) + assert len(counts) != 1, ( + f"every unsourced terminal declares exactly {list(counts)[0]} berth(s) " + f"across {sum(counts.values())} terminals. Real ports differ " + "(ADR-0006)." + ) + + +def test_terminal_structure_is_not_a_corpus_wide_constant(corpus): + """Unsourced ports may not all declare an identical terminal shape. + + The original corpus gave all 119 ports exactly one terminal — including + Barcelona, whose own `port.json` lists eight — so the terminal *array* is + generator output, not merely the fields inside it. + + KNOWN RESIDUE: quarantine did not remove that. Every port still declares + one name-only terminal, because emptying the array would drop 119 + `Terminal` nodes and their `LOCATED_ON` edges from the knowledge graph. + Terminal cardinality is logged as an open item (audit K5) and needs a + referential-integrity decision, not a bulk edit. + + So this test guards the forward direction, which is what it is for: a + future generator must not re-populate terminals with uniform *content*. + The name-only shape is the accepted quarantined baseline; any additional + key appearing uniformly across the unsourced corpus is re-population. + """ + if len(corpus) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("corpus too small for a distribution check") + unsourced = [ + (slug, doc) for slug, doc in corpus if not _sourced_fields(doc) + ] + if len(unsourced) < MIN_CORPUS_FOR_DISTRIBUTION_CHECK: + pytest.skip("too few unsourced ports to judge uniformity") + + #: Entity identity, retained by ADR-0006 and not a passenger-facing claim. + BASELINE_KEYS = {"name"} + + shapes = collections.Counter( + ( + len(doc.get("terminals", [])), + tuple( + sorted( + k + for term in doc.get("terminals", []) + for k, v in term.items() + if v is not None and v != [] and k not in BASELINE_KEYS + ) + ), + ) + for _, doc in unsourced + ) + populated = {shape: n for shape, n in shapes.items() if shape[1]} + assert len(populated) != 1, ( + f"all {sum(populated.values())} unsourced ports share one populated " + f"terminal shape {list(populated)[0]!r}. A uniform terminal structure " + "across a global corpus is generator output (ADR-0006)." + ) + + +def test_synthetic_generators_cannot_repopulate_ports(): + """The two proven generators must fail closed on the port path. + + Asserts behaviour, not text: the module is imported and its refusal + invoked. A generator that silently succeeded would restore every + quarantined value, so the guard is load-bearing and is tested as such. + """ + import importlib + + for module_name in ("tools.mass_populate_knowledge", + "tools.populate_classes_and_ports"): + module = importlib.import_module(module_name) + assert hasattr(module, "refuse_port_population"), ( + f"{module_name} lost its fail-closed port guard" + ) + with pytest.raises(RuntimeError, match="Refusing to populate"): + module.refuse_port_population(1) + + +@pytest.mark.parametrize( + "literal", + ["walking_time_min", "card_acceptance_pct", "distance_to_city_center_m", + "gangway_deck_default", "step_free_access", "negative_intelligence", + BANNED_SOURCE_ID], +) +def test_generator_source_contains_no_port_templates(literal): + """Belt and braces: the templates are gone, not merely unreachable. + + The runtime guard above could be deleted by someone who reads it as + obstruction. Removing the literals means that even then, the generators + cannot reproduce the quarantined fields — the code to do it no longer + exists. Comments are stripped before matching so the explanatory notes + naming these fields do not trip the check. + """ + for name in ("mass_populate_knowledge.py", "populate_classes_and_ports.py"): + path = REPO_ROOT / "tools" / name + code = "\n".join( + line for line in path.read_text(encoding="utf-8").splitlines() + if not line.lstrip().startswith("#") + ) + assert literal not in code, ( + f"{name} still contains the port template literal {literal!r} " + "outside a comment (ADR-0006)." + ) + + +def test_compiler_tolerates_unknown_values(tmp_path): + """The compiler must load a fully-quarantined corpus without raising. + + Restoring a synthetic value to satisfy a consumer is the failure this + guards against; the consumer handles UNKNOWN instead. + + `compile()` writes `cruise_intelligence_db.json` and + `cruise_knowledge_graph.json` into `/data` unconditionally, and + the compiler exposes no output-path option. So the test runs against a + temporary root that exposes the real corpus at `knowledge`: the real data is + exercised, and the writes land in `tmp_path`. A test that mutated tracked + files and then restored them would still be a test that rewrites the working + tree, and would mask genuine drift. + + `expose_knowledge` links where it can and copies where it cannot, so this + runs on platforms without symlink privilege instead of being skipped there. + """ + from timonelo.database.compiler import KnowledgeDBCompiler + + from tests.compiler_sandbox import expose_knowledge + + real_data = REPO_ROOT / "data" + before = { + p.name: p.read_bytes() for p in sorted(real_data.glob("*.json")) + } + + expose_knowledge(tmp_path) + compiler = KnowledgeDBCompiler(root_dir=str(tmp_path)) + compiler.compile() + + assert compiler.ports, "compiler produced no ports" + for slug, port in compiler.ports.items(): + assert "slug" in port, f"{slug}: compiled port lost its slug" + + # The writes must have gone to the temporary root, not the repository. + assert (tmp_path / "data" / "cruise_intelligence_db.json").exists(), ( + "compile() did not write to the temporary root; the redirection " + "assumption in this test no longer holds" + ) + after = {p.name: p.read_bytes() for p in sorted(real_data.glob("*.json"))} + assert before == after, ( + "compile() mutated tracked files under data/ despite the temporary " + f"root: {sorted(k for k in before if before[k] != after.get(k))}" + ) diff --git a/tests/test_source_network.py b/tests/test_source_network.py index 23d3238..2851aca 100644 --- a/tests/test_source_network.py +++ b/tests/test_source_network.py @@ -6,6 +6,8 @@ sys.path.insert(0, REPO_ROOT) from src.timonelo.database.compiler import KnowledgeDBCompiler + +from tests.compiler_sandbox import sandbox_root from src.timonelo.database.sources_schema import SourceCategory, AccessMethod, SourceEntity from src.timonelo.database.sources_dashboard import SourcesDashboard @@ -13,7 +15,8 @@ class TestSourceNetwork(unittest.TestCase): @classmethod def setUpClass(cls): - compiler = KnowledgeDBCompiler(REPO_ROOT) + # Sandboxed root: see tests/compiler_sandbox.py. + compiler = KnowledgeDBCompiler(sandbox_root()) cls.db = compiler.compile() def test_sources_network_ingestion(self): diff --git a/tools/generate_frontend_bridge.py b/tools/generate_frontend_bridge.py index 7332f5a..86e15e1 100644 --- a/tools/generate_frontend_bridge.py +++ b/tools/generate_frontend_bridge.py @@ -127,83 +127,106 @@ def generate_bridge(): print(f" [OK] Generated frontend/src/generated/fleet.ts with {len(fleet_vessels)} ships.") # 3. Generate TypeScript Port Registry + # + # TRUST BOUNDARY. This bridge propagates canonical knowledge to the + # frontend. It may not originate evidence authority, and it may not + # substitute a plausible value for a missing one -- a default that looks + # like data is worse on a passenger surface than a visible gap, because a + # gap invites checking and a confident wrong value suppresses it. + # + # Removed here (see ADR-0006 and audit U-1): hardcoded berths, + # gangwayDeckDefault=5, distanceToCenterM=500, walkingTimeMin=10, + # stepFreeAccess=True, cardAcceptancePct=98, a currency and emergencyPhone + # derived from a country allow-list, blanket transitNote/airportTransit + # accessibility claims, a two-entry negativeIntelligence template, a + # callingShips list naming three MSC vessels for every port on earth, and + # an officialSource naming Timonelo's own domain as the port authority + # under trustLevel OFFICIAL. + # + # `un_locode` previously fell back to "ITGOA", silently relabelling any + # port without a code as Genoa. There is no fallback now. port_records = [] for slug, p in ports.items(): - name = p.get("name", slug.title()) - locode = p.get("un_locode", "ITGOA") - country = p.get("country", "Italy") - region = p.get("region", "Mediterranean") - term = p.get("terminal_name", p.get("terminal", "Cruise Terminal")) + terminals = p.get("terminals") or [] + first_terminal = terminals[0] if terminals else {} + logistics = p.get("logistics") or {} + + # Provenance is propagated, never minted. A source record survives to + # the frontend only if the knowledge layer carries one scoped to a + # named field; `field: "all"` is not provenance (ADR-0006 D2) and + # OFFICIAL is a property of evidence, not a presentation default. + official_source = None + for src in p.get("sources") or []: + if src.get("field") in (None, "all"): + continue + if not src.get("source_id"): + continue + official_source = { + "authority": src.get("authority"), + "url": src.get("url"), + "sourceId": src["source_id"], + "field": src["field"], + "trustLevel": src.get("trust_level"), + } + break port_records.append({ "slug": slug, - "name": name, - "unLocode": locode, - "country": country, - "region": region, - "headline": f"Strategic maritime cruise port gateway for {region}.", - "terminalName": term, - "berths": ["Berth 1", "Berth 2"], - "gangwayDeckDefault": 5, - "distanceToCenterM": 500, - "walkingTimeMin": 10, - "stepFreeAccess": True, - "transitNote": "Official shuttle, public transit, or level pedestrian walkways available.", - "airportTransit": "Regional airport connection available via express bus or taxi.", - "currency": "Euro (€ / EUR)" if country in ["Italy", "Spain", "France", "Malta", "Germany", "Portugal"] else "USD ($)", - "cardAcceptancePct": 98, - "emergencyPhone": "112" if country in ["Italy", "Spain", "France", "Malta", "Germany", "Portugal"] else "911", - "negativeIntelligence": [ - "Turn on Airplane Mode beyond port breakwaters to avoid satellite cellular roaming.", - "Always use official port taxi stands with metered or fixed city fares." - ], - "officialSource": { - "authority": f"{name} Port Authority", - "url": "https://www.timonelo.com", - "trustLevel": "OFFICIAL", - }, - "callingShips": [ - {"slug": "msc-bellissima", "name": "MSC Bellissima"}, - {"slug": "msc-world-europa", "name": "MSC World Europa"}, - {"slug": "msc-meraviglia", "name": "MSC Meraviglia"} - ], + "name": p.get("name"), + "unLocode": p.get("un_locode"), + "country": p.get("country"), + "region": p.get("region"), + "terminalName": first_terminal.get("name"), + "berths": first_terminal.get("berths") or [], + "gangwayDeckDefault": first_terminal.get("gangway_deck_default"), + "distanceToCenterM": first_terminal.get("distance_to_city_center_m"), + "walkingTimeMin": first_terminal.get("walking_time_min"), + "stepFreeAccess": first_terminal.get("step_free_access"), + "currency": logistics.get("currency"), + "cardAcceptancePct": logistics.get("card_acceptance_pct"), + "emergencyPhone": logistics.get("emergency_phone"), + "negativeIntelligence": p.get("negative_intelligence") or [], + "officialSource": official_source, + "callingShips": [], }) ports_ts_content = f"""// AUTO-GENERATED BY tools/generate_frontend_bridge.py // DO NOT EDIT MANUALLY. SOURCE: data/cruise_intelligence_db.json +// Nullable by design. `null` means the knowledge layer holds no evidence for +// this field; it must render as unavailable, never as a substituted default. export interface PortData {{ slug: string; - name: string; - unLocode: string; - country: string; - region: string; - headline: string; - terminalName: string; + name: string | null; + unLocode: string | null; + country: string | null; + region: string | null; + terminalName: string | null; berths: string[]; - gangwayDeckDefault: number; - distanceToCenterM: number; - walkingTimeMin: number; - stepFreeAccess: boolean; - transitNote: string; - airportTransit: string; - currency: string; - cardAcceptancePct: number; - emergencyPhone: string; + gangwayDeckDefault: number | null; + distanceToCenterM: number | null; + walkingTimeMin: number | null; + stepFreeAccess: boolean | null; + currency: string | null; + cardAcceptancePct: number | null; + emergencyPhone: string | null; negativeIntelligence: string[]; officialSource: {{ - authority: string; - url: string; - trustLevel: 'OFFICIAL' | 'VERIFIED'; - }}; + authority: string | null; + url: string | null; + sourceId: string; + field: string; + trustLevel: string | null; + }} | null; callingShips: {{ slug: string; name: string }}[]; }} export const PORTS_REGISTRY: PortData[] = {json.dumps(port_records, indent=2, sort_keys=True, ensure_ascii=False)}; -export function getPortBySlug(slug: string): PortData {{ - const found = PORTS_REGISTRY.find((p) => p.slug === slug); - return found || PORTS_REGISTRY[0]; +// Returns undefined for an unknown slug. Returning PORTS_REGISTRY[0] would +// silently present one port's data under another port's name. +export function getPortBySlug(slug: string): PortData | undefined {{ + return PORTS_REGISTRY.find((p) => p.slug === slug); }} """ with open(os.path.join(FRONTEND_GEN_DIR, "ports.ts"), "w", encoding="utf-8") as f: diff --git a/tools/mass_populate_knowledge.py b/tools/mass_populate_knowledge.py index 7c37b08..ebd696b 100644 --- a/tools/mass_populate_knowledge.py +++ b/tools/mass_populate_knowledge.py @@ -150,7 +150,43 @@ ] # 3. POPULATE EXECUTION SCRIPT + +def refuse_port_population(port_count: int) -> None: + """Fail closed rather than regenerate the synthetic port identity layer. + + An error is the correct output here. The alternative -- emitting the + fields with null values instead of literals -- would still overwrite 119 + tracked files, discarding the explicit nulls that record which claims were + asserted and withdrawn, and would leave a bulk writer pointed at the + knowledge layer for a job that no longer exists. + + Port identity now requires field-scoped evidence per port. There is no + bulk path to that, so there is no safe way to run this. + """ + raise RuntimeError( + f"Refusing to populate {port_count} port identity packs.\n" + "\n" + "This generator wrote template constants into every " + "knowledge/ports//identity.json and attested them as OFFICIAL " + "with a field:'all' source record. Those values were quarantined by " + "ADR-0006 and the templates have been removed.\n" + "\n" + "Port identity facts now require field-scoped evidence per port. To " + "add a port, create its identity.json with entity fields only " + "(slug, name, un_locode, country, region, coordinates) and leave " + "every passenger-facing field absent until sourced.\n" + "\n" + "See docs/adr/ADR-0006.md and " + "docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md" + ) + + def populate_knowledge_base(): + # Fail closed before ANY write. The port guard alone left cruise-lines + # rewritten by the time it fired, which is a partial mutation of tracked + # knowledge from a script that cannot complete. Refuse up front instead. + refuse_port_population(len(PORTS_EXPANSION)) + print("=" * 60) print(" TIMONELO MASTER KNOWLEDGE POPULATION ENGINE") print("=" * 60) @@ -165,46 +201,24 @@ def populate_knowledge_base(): print(f"[OK] Populated {len(CRUISE_LINES)} Cruise Lines.") # 2. Ports - ports_dir = os.path.join(KNOWLEDGE_DIR, "ports") - os.makedirs(ports_dir, exist_ok=True) - for p in PORTS_EXPANSION: - slug = p["slug"] - port_pack_dir = os.path.join(ports_dir, slug) - os.makedirs(port_pack_dir, exist_ok=True) - identity = { - "slug": slug, - "name": p["name"], - "un_locode": p["un_locode"], - "country": p["country"], - "region": p["region"], - "coordinates": {"latitude": p["lat"], "longitude": p["lon"]}, - "timezone": "UTC", - "terminals": [ - { - "name": p["terminal"], - "berths": [f"{slug.title()} Berth 1", f"{slug.title()} Berth 2"], - "gangway_deck_default": 5 if "River" not in p["region"] else 2, - "distance_to_city_center_m": 500, - "walking_time_min": 10, - "step_free_access": True, - } - ], - "logistics": { - "currency": "EUR" if p["country"] in ["Italy", "Spain", "France", "Germany", "Portugal", "Greece", "Malta", "Cyprus", "Netherlands", "Belgium", "Austria", "Slovakia", "Finland", "Estonia", "Latvia"] else "USD" if p["country"] in ["United States", "Puerto Rico"] else "GBP" if p["country"] == "United Kingdom" else "NOK" if p["country"] == "Norway" else "Local", - "card_acceptance_pct": 98, - "emergency_phone": "112" if p["country"] not in ["United States", "Puerto Rico"] else "911", - }, - "negative_intelligence": [ - f"Check terminal berth assignment upon morning arrival in {p['name'].split('(')[0].strip()}.", - "Keep ship ID card and government passport securely zipped during shore transit." - ], - "sources": [ - {"field": "all", "source_id": "src:official-port-authority", "trust_level": "OFFICIAL", "retrieved_at": "2026-08-16T12:00:00Z"} - ], - } - with open(os.path.join(port_pack_dir, "identity.json"), "w", encoding="utf-8") as f: - json.dump(identity, f, indent=2, sort_keys=True, ensure_ascii=False) - print(f"[OK] Populated {len(PORTS_EXPANSION)} Strategic Cruise Ports.") + # + # RETIRED. This block previously synthesised every passenger-facing field + # of knowledge/ports//identity.json from hardcoded literals -- + # timezone="UTC", gangway_deck_default=5 (2 for river ports), + # distance_to_city_center_m=500, walking_time_min=10, + # card_acceptance_pct=98, step_free_access=True, berths named from the + # slug, negative_intelligence from an f-string template -- and stamped the + # result with a blanket source record (field:"all", + # source_id:"src:official-port-authority", trust_level:"OFFICIAL"). + # + # It also derived logistics.emergency_phone from a country allow-list with + # an else-branch, which published 112 for Mexico, Barbados, the Cayman + # Islands and Israel. All incorrect, all under OFFICIAL. See ADR-0006. + # + # PORTS_EXPANSION is kept above because it records where the port slugs, + # names, coordinates and UN/LOCODEs entered the repository. That data is + # unvalidated candidate identity, not canon, and nothing here may write it + # back as fact. print("=" * 60) print("Knowledge population complete. Ready for compiler & graph build.") diff --git a/tools/populate_classes_and_ports.py b/tools/populate_classes_and_ports.py index 2b48e30..13591b6 100644 --- a/tools/populate_classes_and_ports.py +++ b/tools/populate_classes_and_ports.py @@ -35,7 +35,41 @@ ] + +def refuse_port_population(port_count: int) -> None: + """Fail closed rather than regenerate the synthetic port identity layer. + + An error is the correct output here. The alternative -- emitting the + fields with null values instead of literals -- would still overwrite 119 + tracked files, discarding the explicit nulls that record which claims were + asserted and withdrawn, and would leave a bulk writer pointed at the + knowledge layer for a job that no longer exists. + + Port identity now requires field-scoped evidence per port. There is no + bulk path to that, so there is no safe way to run this. + """ + raise RuntimeError( + f"Refusing to populate {port_count} port identity packs.\n" + "\n" + "This generator wrote template constants into every " + "knowledge/ports//identity.json and attested them as OFFICIAL " + "with a field:'all' source record. Those values were quarantined by " + "ADR-0006 and the templates have been removed.\n" + "\n" + "Port identity facts now require field-scoped evidence per port. To " + "add a port, create its identity.json with entity fields only " + "(slug, name, un_locode, country, region, coordinates) and leave " + "every passenger-facing field absent until sourced.\n" + "\n" + "See docs/adr/ADR-0006.md and " + "docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md" + ) + + def populate_classes_and_extra_ports(): + # Fail closed before ANY write; see the note in mass_populate_knowledge.py. + refuse_port_population(len(ADDITIONAL_PORTS)) + # 1. Ship Classes (25 Classes) classes_dir = os.path.join(KNOWLEDGE_DIR, "ship-classes") os.makedirs(classes_dir, exist_ok=True) @@ -47,45 +81,20 @@ def populate_classes_and_extra_ports(): print(f"[OK] Populated {len(SHIP_CLASSES_DATA)} Canonical Ship Classes.") # 2. Additional Strategic Ports - ports_dir = os.path.join(KNOWLEDGE_DIR, "ports") - for p in ADDITIONAL_PORTS: - slug = p["slug"] - port_pack_dir = os.path.join(ports_dir, slug) - os.makedirs(port_pack_dir, exist_ok=True) - identity = { - "slug": slug, - "name": p["name"], - "un_locode": p["un_locode"], - "country": p["country"], - "region": p["region"], - "coordinates": {"latitude": p["lat"], "longitude": p["lon"]}, - "timezone": "UTC", - "terminals": [ - { - "name": p["terminal"], - "berths": [f"{slug.title()} Pier 1"], - "gangway_deck_default": 5, - "distance_to_city_center_m": 800, - "walking_time_min": 10, - "step_free_access": True, - } - ], - "logistics": { - "currency": "USD" if p["country"] in ["United States", "Puerto Rico", "Jamaica"] else "EUR" if p["country"] in ["Italy", "Germany"] else "AUD" if p["country"] == "Australia" else "SGD" if p["country"] == "Singapore" else "MXN" if p["country"] == "Mexico" else "Local", - "card_acceptance_pct": 98, - "emergency_phone": "911" if p["country"] in ["United States", "Canada", "Mexico", "Argentina"] else "112" if p["country"] in ["Italy", "Germany", "United Kingdom"] else "999", - }, - "negative_intelligence": [ - f"Verify pier location in {p['name'].split('(')[0].strip()}.", - "Keep ship ID card securely zipped." - ], - "sources": [ - {"field": "all", "source_id": "src:official-port-authority", "trust_level": "OFFICIAL", "retrieved_at": "2026-08-16T12:00:00Z"} - ], - } - with open(os.path.join(port_pack_dir, "identity.json"), "w", encoding="utf-8") as f: - json.dump(identity, f, indent=2, sort_keys=True, ensure_ascii=False) - print(f"[OK] Populated {len(ADDITIONAL_PORTS)} Additional Global Strategic Ports.") + # + # RETIRED. This block previously synthesised every passenger-facing field + # of knowledge/ports//identity.json from hardcoded literals -- + # gangway_deck_default=5, distance_to_city_center_m=800, + # walking_time_min=10, card_acceptance_pct=98, step_free_access=True, + # berths named from the slug, negative_intelligence from an f-string + # template -- and stamped the result with a blanket source record + # (field:"all", source_id:"src:official-port-authority", + # trust_level:"OFFICIAL"). None of it had evidence. See ADR-0006. + # + # ADDITIONAL_PORTS is kept above because it records where the port slugs, + # names, coordinates and UN/LOCODEs entered the repository. That data is + # unvalidated candidate identity, not canon, and nothing here may write it + # back as fact. if __name__ == "__main__":