From c3059aedcfbdd815a7bdb2e020bb9418d91fca78 Mon Sep 17 00:00:00 2001
From: Claude
Date: Mon, 24 Aug 2026 13:41:42 +0000
Subject: [PATCH 1/5] chore(ports): quarantine synthetic port identity layer
(ADR-0006)
All 119 knowledge/ports/*/identity.json files were emitted by two bulk
generators (tools/mass_populate_knowledge.py, 101 ports;
tools/populate_classes_and_ports.py, 18 ports) that hardcode template
constants. Corpus-wide, timezone is "UTC" 119/119, walking_time_min is
10 119/119, card_acceptance_pct is 98 119/119, and every port carries an
identical blanket source record:
{"field": "all", "source_id": "src:official-port-authority",
"trust_level": "OFFICIAL", "retrieved_at": "2026-08-16T12:00:00Z"}
field:"all" attests no field in particular; src:official-port-authority
resolves to no artifact; and OFFICIAL was applied by a generator to values
it invented. The defect is invisible per-file and only appears in the
distribution across the corpus.
Quarantines the synthetic fields to their fail-closed state (null scalars,
empty lists) and removes the blanket source records. Keys are retained
rather than deleted so the data records that a claim was asserted and
withdrawn. Entity identity fields are preserved for referential integrity
and explicitly NOT promoted to trusted facts; no provenance is invented
for them.
Extends scope to logistics.emergency_phone and logistics.currency, which
were not in the original plan. emergency_phone is a generator else-branch
yielding 112 for Mexico, Barbados, Cayman Islands and Israel -- all
incorrect, all published under OFFICIAL.
Enforcement is 13 corpus-wide, distribution-based invariants; a per-file
assertion cannot distinguish a researched 10 from a template 10.
Not fixed here: tools/generate_frontend_bridge.py hardcodes the same
values independently, so ports.ts stays contaminated until the frontend
contract is changed. data/ is excluded because it is already stale on
develop independently of this change. Both are documented in the audit.
Refs: docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md
---
docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md | 365 ++++++++++++++++++
docs/adr/ADR-0006.md | 227 +++++++++++
knowledge/ports/ajaccio/identity.json | 35 +-
knowledge/ports/akureyri/identity.json | 35 +-
knowledge/ports/alesund/identity.json | 35 +-
knowledge/ports/amsterdam/identity.json | 35 +-
knowledge/ports/arrecife/identity.json | 35 +-
knowledge/ports/barcelona/identity.json | 35 +-
knowledge/ports/bari/identity.json | 34 +-
knowledge/ports/basel/identity.json | 35 +-
.../ports/bayonne-cape-liberty/identity.json | 35 +-
knowledge/ports/bergen/identity.json | 35 +-
knowledge/ports/boston/identity.json | 35 +-
knowledge/ports/bratislava/identity.json | 35 +-
knowledge/ports/bremerhaven/identity.json | 34 +-
knowledge/ports/bridgetown/identity.json | 35 +-
knowledge/ports/budapest/identity.json | 35 +-
knowledge/ports/buenos-aires/identity.json | 34 +-
knowledge/ports/cabo-san-lucas/identity.json | 34 +-
knowledge/ports/cadiz/identity.json | 35 +-
knowledge/ports/cagliari/identity.json | 35 +-
knowledge/ports/cannes/identity.json | 35 +-
knowledge/ports/castries/identity.json | 35 +-
knowledge/ports/civitavecchia/identity.json | 35 +-
knowledge/ports/cologne/identity.json | 35 +-
knowledge/ports/copenhagen/identity.json | 35 +-
knowledge/ports/corfu/identity.json | 35 +-
knowledge/ports/costa-maya/identity.json | 35 +-
knowledge/ports/cozumel/identity.json | 35 +-
knowledge/ports/dover/identity.json | 35 +-
knowledge/ports/dubrovnik/identity.json | 35 +-
knowledge/ports/ensenada/identity.json | 34 +-
knowledge/ports/flam/identity.json | 35 +-
knowledge/ports/fort-lauderdale/identity.json | 35 +-
knowledge/ports/funchal/identity.json | 35 +-
knowledge/ports/galveston/identity.json | 35 +-
knowledge/ports/geiranger/identity.json | 35 +-
knowledge/ports/genoa/identity.json | 35 +-
knowledge/ports/grand-cayman/identity.json | 35 +-
knowledge/ports/haifa/identity.json | 35 +-
knowledge/ports/hamburg/identity.json | 35 +-
knowledge/ports/helsinki/identity.json | 35 +-
knowledge/ports/heraklion/identity.json | 35 +-
.../ports/honDefault-nordkapp/identity.json | 35 +-
knowledge/ports/hong-kong/identity.json | 34 +-
knowledge/ports/ibiza/identity.json | 35 +-
knowledge/ports/istanbul/identity.json | 35 +-
knowledge/ports/juneau/identity.json | 35 +-
knowledge/ports/ketchikan/identity.json | 35 +-
knowledge/ports/kiel/identity.json | 35 +-
knowledge/ports/koblenz/identity.json | 35 +-
knowledge/ports/kotor/identity.json | 35 +-
knowledge/ports/kusadasi/identity.json | 35 +-
knowledge/ports/la-spezia/identity.json | 35 +-
knowledge/ports/las-palmas/identity.json | 35 +-
knowledge/ports/le-havre/identity.json | 35 +-
knowledge/ports/limassol/identity.json | 35 +-
knowledge/ports/lisbon/identity.json | 35 +-
knowledge/ports/livorno/identity.json | 35 +-
knowledge/ports/london/identity.json | 34 +-
knowledge/ports/los-angeles/identity.json | 34 +-
knowledge/ports/malaga/identity.json | 35 +-
knowledge/ports/marseille/identity.json | 35 +-
knowledge/ports/mazatlan/identity.json | 34 +-
knowledge/ports/messina/identity.json | 35 +-
knowledge/ports/miami/identity.json | 35 +-
knowledge/ports/monaco/identity.json | 35 +-
knowledge/ports/mykonos/identity.json | 35 +-
knowledge/ports/naples/identity.json | 35 +-
knowledge/ports/nassau/identity.json | 35 +-
knowledge/ports/new-orleans/identity.json | 35 +-
knowledge/ports/new-york/identity.json | 35 +-
.../ports/nice-villefranche/identity.json | 35 +-
knowledge/ports/ocho-rios/identity.json | 34 +-
knowledge/ports/oranjestad/identity.json | 35 +-
knowledge/ports/oslo/identity.json | 35 +-
knowledge/ports/palermo/identity.json | 35 +-
.../ports/palma-de-mallorca/identity.json | 35 +-
knowledge/ports/passau/identity.json | 35 +-
knowledge/ports/pinhao/identity.json | 35 +-
knowledge/ports/piraeus/identity.json | 35 +-
knowledge/ports/port-canaveral/identity.json | 35 +-
knowledge/ports/port-everglades/identity.json | 34 +-
knowledge/ports/porto/identity.json | 35 +-
knowledge/ports/puerto-vallarta/identity.json | 34 +-
knowledge/ports/regua/identity.json | 35 +-
knowledge/ports/reykjavik/identity.json | 35 +-
knowledge/ports/rhodes/identity.json | 35 +-
knowledge/ports/riga/identity.json | 35 +-
knowledge/ports/roatan/identity.json | 35 +-
knowledge/ports/rotterdam/identity.json | 35 +-
knowledge/ports/san-juan/identity.json | 35 +-
.../santa-cruz-de-tenerife/identity.json | 35 +-
knowledge/ports/santorini/identity.json | 35 +-
knowledge/ports/seattle/identity.json | 35 +-
knowledge/ports/shanghai/identity.json | 34 +-
knowledge/ports/singapore/identity.json | 34 +-
knowledge/ports/skagway/identity.json | 35 +-
knowledge/ports/southampton/identity.json | 35 +-
knowledge/ports/split/identity.json | 35 +-
knowledge/ports/st-maarten/identity.json | 35 +-
knowledge/ports/st-thomas/identity.json | 35 +-
knowledge/ports/stavanger/identity.json | 35 +-
knowledge/ports/stockholm/identity.json | 35 +-
knowledge/ports/strasbourg/identity.json | 35 +-
knowledge/ports/sydney/identity.json | 34 +-
knowledge/ports/tallinn/identity.json | 35 +-
knowledge/ports/tampa/identity.json | 35 +-
knowledge/ports/trieste/identity.json | 34 +-
knowledge/ports/tromso/identity.json | 35 +-
knowledge/ports/ushuaia/identity.json | 34 +-
knowledge/ports/valencia/identity.json | 35 +-
knowledge/ports/valletta/identity.json | 35 +-
knowledge/ports/vancouver/identity.json | 35 +-
knowledge/ports/venice-ravenna/identity.json | 35 +-
knowledge/ports/venice-trieste/identity.json | 35 +-
knowledge/ports/victoria/identity.json | 34 +-
knowledge/ports/vienna/identity.json | 35 +-
.../ports/warnemunde-rostock/identity.json | 35 +-
knowledge/ports/willemstad/identity.json | 35 +-
knowledge/ports/zeebrugge/identity.json | 35 +-
tests/test_port_identity_quarantine.py | 237 ++++++++++++
122 files changed, 2138 insertions(+), 2838 deletions(-)
create mode 100644 docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md
create mode 100644 docs/adr/ADR-0006.md
create mode 100644 tests/test_port_identity_quarantine.py
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/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/test_port_identity_quarantine.py b/tests/test_port_identity_quarantine.py
new file mode 100644
index 0000000..c37c80d
--- /dev/null
+++ b/tests/test_port_identity_quarantine.py
@@ -0,0 +1,237 @@
+"""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_compiler_tolerates_unknown_values():
+ """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.
+ """
+ from timonelo.database.compiler import KnowledgeDBCompiler
+
+ compiler = KnowledgeDBCompiler(root_dir=str(REPO_ROOT))
+ 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"
From 5b7152f3116defef52f0a138d9005a58d2f85ac6 Mon Sep 17 00:00:00 2001
From: Claude
Date: Mon, 24 Aug 2026 13:53:07 +0000
Subject: [PATCH 2/5] chore(ports): retire synthetic port generators, make
compiler tests side-effect-free
Follow-up to ADR-0006. Three changes.
1. Both proven generators fail closed on the port path.
tools/mass_populate_knowledge.py (101 ports) and
tools/populate_classes_and_ports.py (18 ports) could still recreate every
quarantined value. Their port-identity construction is removed and replaced
with refuse_port_population(), which raises with an explanation and a
pointer to the ADR.
The guard sits at the top of each entry function, before any write. Placed
at the port section instead, a run rewrote 45 cruise-line and ship-class
files before refusing -- a partial mutation of tracked knowledge by a script
that cannot complete.
The template literals are deleted as well as guarded, so the generators
cannot reproduce the fields even if someone removes the guard as
obstruction. PORTS_EXPANSION and ADDITIONAL_PORTS are kept: they record
where the slugs, names, coordinates and LOCODEs entered the repository, and
remain unvalidated candidate identity.
2. Compiler tests no longer mutate the working tree.
compile() writes data/cruise_intelligence_db.json and
data/cruise_knowledge_graph.json unconditionally and exposes no output-path
option, so four tests rewrote two tracked files on every run. Since those
artifacts are already stale on develop, this destroyed the evidence of that
drift and made git status after a test run meaningless.
tests/compiler_sandbox.py supplies a temporary root whose knowledge/ is a
symlink to the real corpus: real data in, artifacts out to the sandbox.
Nothing is restored afterwards, because nothing is modified -- restoring
tracked files after mutating them is still mutation.
3. Four new corpus invariants.
step_free_access uniformity and unsourced true claims; slug-interpolated
berth names; uniform berth counts; uniform populated terminal shape. Plus
behavioural and source-level checks that the generators stay retired.
Accessibility gets its own pair rather than joining the numeric checks:
a wrong walking time costs ten minutes, a wrong step-free claim sends a
wheelchair user to a gangway they cannot board.
Known residue, not fixed here: all 119 ports still declare exactly one
name-only terminal. Emptying the array would drop 119 Terminal nodes and their
LOCATED_ON edges from the graph, so terminal cardinality needs a referential
integrity decision rather than a bulk edit. Audit K5; documented in the test.
Tests 890 -> 903. data/ and knowledge/ unmodified by the full suite.
Refs: docs/adr/ADR-0006.md
---
tests/compiler_sandbox.py | 48 ++++++
tests/test_cruise_intelligence_db.py | 6 +-
tests/test_live_fleet_operations.py | 5 +-
tests/test_port_identity_quarantine.py | 223 ++++++++++++++++++++++++-
tests/test_source_network.py | 5 +-
tools/mass_populate_knowledge.py | 94 ++++++-----
tools/populate_classes_and_ports.py | 87 +++++-----
7 files changed, 384 insertions(+), 84 deletions(-)
create mode 100644 tests/compiler_sandbox.py
diff --git a/tests/compiler_sandbox.py b/tests/compiler_sandbox.py
new file mode 100644
index 0000000..4bdd901
--- /dev/null
+++ b/tests/compiler_sandbox.py
@@ -0,0 +1,48 @@
+"""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 whose `knowledge` is a symlink
+to the real corpus. 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.
+"""
+
+from __future__ import annotations
+
+import pathlib
+import tempfile
+
+REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
+
+
+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)
+ (root / "knowledge").symlink_to(REPO_ROOT / "knowledge")
+ 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_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
index c37c80d..0ab4097 100644
--- a/tests/test_port_identity_quarantine.py
+++ b/tests/test_port_identity_quarantine.py
@@ -222,16 +222,235 @@ def test_unsourced_identity_publishes_no_facts(corpus):
)
-def test_compiler_tolerates_unknown_values():
+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 whose `knowledge` is a symlink to the real corpus: 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.
"""
from timonelo.database.compiler import KnowledgeDBCompiler
- compiler = KnowledgeDBCompiler(root_dir=str(REPO_ROOT))
+ real_data = REPO_ROOT / "data"
+ before = {
+ p.name: p.read_bytes() for p in sorted(real_data.glob("*.json"))
+ }
+
+ (tmp_path / "knowledge").symlink_to(REPO_ROOT / "knowledge")
+ 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/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__":
From 55c2059cb3fdd052f9cef250bb4adad062741164 Mon Sep 17 00:00:00 2001
From: Claude
Date: Mon, 24 Aug 2026 14:13:11 +0000
Subject: [PATCH 3/5] fix(bridge): stop the frontend bridge originating
passenger-facing facts
Audit U-1. tools/generate_frontend_bridge.py did not read passenger-facing
port values from the knowledge layer -- it hardcoded them at generation time.
Quarantining knowledge/ports/ therefore left the passenger surface unchanged,
because the fabrication happened downstream of the layer being governed.
Removed from the bridge: berths [Berth 1, Berth 2], gangwayDeckDefault=5,
distanceToCenterM=500, walkingTimeMin=10, stepFreeAccess=True,
cardAcceptancePct=98, currency and emergencyPhone from a country allow-list,
blanket transitNote/airportTransit accessibility claims, a two-entry
negativeIntelligence template, and a callingShips list naming three MSC
vessels for every port on earth.
Also removed: officialSource, which named Timonelo's own domain as the port
authority under trustLevel OFFICIAL, and the p.get(un_locode, ITGOA) fallback
that silently relabelled any codeless port as Genoa.
The bridge now propagates provenance and never originates it. 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). Everything else is
null. Regenerated ports.ts: 119 ports, 0 non-null for every fabricated field,
the one remaining ITGOA being Genoa's own record.
Contract changes, kept as narrow as the nulls require. PortData and
CuratedPort fields become nullable. getPortBySlug returns undefined for an
unknown slug rather than PORTS_REGISTRY[0], which presented one port's data
under another port's name.
Consumers fixed rather than data restored. frontend/src/ports.ts dropped its
own fallbacks -- slug.toUpperCase() rendered YOKOHAMA in the UN/LOCODE field
for a port absent from the knowledge layer, and Europe / Global, EUR and 98
were presentation defaults shaped like facts. PortExplorer renders unknown /
unbekannt where a value is missing, and no longer appends (step-free) to the
walking-time line: stepFreeAccess is null for every port, so the claim had
nothing behind it.
Not included: frontend/src/generated/database.json. Regenerating it pulls in
the pre-existing msc-bellissima and msc-meraviglia drift documented as U-2,
and nothing in the frontend imports it.
Backend 903 -> 922. Frontend 91 passed, typecheck 400 errors unchanged from
baseline, production build green. data/ and knowledge/ untouched.
Refs: docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md
---
frontend/src/components/PortExplorer.tsx | 10 +-
.../src/components/UniversalSearchModal.tsx | 4 +-
frontend/src/generated/ports.ts | 7096 +++++------------
frontend/src/ports.ts | 38 +-
tests/test_frontend_bridge_trust_boundary.py | 226 +
tools/generate_frontend_bridge.py | 137 +-
6 files changed, 2339 insertions(+), 5172 deletions(-)
create mode 100644 tests/test_frontend_bridge_trust_boundary.py
diff --git a/frontend/src/components/PortExplorer.tsx b/frontend/src/components/PortExplorer.tsx
index 7899925..4cb144a 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})
+ )}
))}
@@ -96,8 +98,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')}
@@ -135,7 +137,7 @@ export function PortExplorer({ initialPortSlug, onSelectShip }: PortExplorerProp
{(selectedPort.walkingTimeMin ?? 0) > 0
- ? (isGerman ? `ca. ${selectedPort.walkingTimeMin} Min. Gehzeit (stufenlos)` : `approx. ${selectedPort.walkingTimeMin} min walk (step-free)`)
+ ? (isGerman ? `ca. ${selectedPort.walkingTimeMin} Min. Gehzeit` : `approx. ${selectedPort.walkingTimeMin} min walk`)
: (isGerman ? 'Shuttle-Transfer oder Taxi empfohlen' : 'Shuttle transfer or taxi recommended')}
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..bb03860 100644
--- a/frontend/src/ports.ts
+++ b/frontend/src/ports.ts
@@ -7,9 +7,9 @@ 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;
@@ -18,13 +18,13 @@ export interface CuratedPort {
gangwayDeck: number | null;
distanceToCenterKm: number | null;
walkingTimeMin: number | null;
- stepFreeAccess: boolean;
+ stepFreeAccess: boolean | null;
transitNoteEn: string;
transitNoteDe: string;
airportTransitEn: string;
airportTransitDe: string;
- currency: string;
- cardAcceptancePct: number;
+ currency: string | null;
+ cardAcceptancePct: number | null;
emergencyPhone: string;
policePhone: string;
callingShips: { slug: string; name: string }[];
@@ -247,13 +247,18 @@ export const PORTS_REGISTRY: CuratedPort[] = [
];
const raw = RAW_PORTS.find((p) => 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,
@@ -262,13 +267,13 @@ export const PORTS_REGISTRY: CuratedPort[] = [
gangwayDeck: custom.gangwayDeck,
distanceToCenterKm: custom.distanceKm,
walkingTimeMin: custom.walkingMin,
- stepFreeAccess: true,
+ stepFreeAccess: null,
transitNoteDe: custom.transitDe,
transitNoteEn: custom.transitEn,
airportTransitDe: custom.airportDe,
airportTransitEn: custom.airportEn,
- currency: raw ? raw.currency : 'EUR (€)',
- cardAcceptancePct: raw ? raw.cardAcceptancePct : 98,
+ currency: raw?.currency ?? null,
+ cardAcceptancePct: raw?.cardAcceptancePct ?? null,
emergencyPhone: custom.emergency,
policePhone: custom.police,
callingShips,
@@ -277,7 +282,8 @@ export const PORTS_REGISTRY: CuratedPort[] = [
};
});
-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/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/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:
From 588611be15902fa23a2bbabd5b88f0688f2b3a7b Mon Sep 17 00:00:00 2001
From: Claude
Date: Mon, 24 Aug 2026 14:32:00 +0000
Subject: [PATCH 4/5] fix(ports): keep unknown values unknown on the passenger
surface
Audit U-1 follow-up.
1. Walking time is now three-state.
`(walkingTimeMin ?? 0) > 0` collapsed null and 0 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, that a taxi is
warranted, or that walking is impractical. Unknown now renders as
"Walking time unknown" / "Gehzeit unbekannt".
0 is treated as unknown too. It appears once in the data (Shanghai, 24 km)
as an informal sentinel for "too far to walk", but that meaning is
documented nowhere and is indistinguishable at the render site from a
missing value.
2. CURATED_PORT_STORIES no longer supplies operational facts.
The block held hand-written passenger facts for six ports with no
provenance model. Descriptive framing stays; anything that changes what a
passenger does is wired to null: walkingMin, distanceKm, gangwayDeck,
terminalPier, emergency, police, transit and airport notes, essentials.
The literals stay in the source block as candidates for a future sourced
pipeline rather than being deleted.
3. Four story texts asserted the same facts in prose.
Neutralising the structured fields while the narrative still read "From
Gangway Deck 5, the city centre is accessible in a 15-minute walk" and
"offers completely step-free access" would have been cosmetic. Genoa
(deck, walking time), Yokohama (step-free, walking distance) and Shanghai
(berth assignment) lost those clauses and kept their framing.
Render sites guarded so absent values produce an explicit statement rather
than an empty panel: terminal pier, emergency numbers, transit cards, and the
LOCODE parenthesis that rendered as "Yokohama ()".
Not addressed: Barcelona's story describes the PortBus shuttle service, which
is a transit claim without evidence. It reads as geographic framing rather
than advice, and deleting it shades into rewriting editorial copy, so it is
reported rather than changed.
Frontend 91 -> 113. Backend 922 unchanged. Typecheck 400, identical to
baseline. Build green. data/, knowledge/ and package-lock.json untouched.
Refs: docs/PORT_IDENTITY_CORPUS_AUDIT_2026-08-24.md
---
.../components/PortExplorer.trust.test.tsx | 196 ++++++++++++++++++
frontend/src/components/PortExplorer.tsx | 89 ++++++--
frontend/src/ports.ts | 57 ++---
3 files changed, 296 insertions(+), 46 deletions(-)
create mode 100644 frontend/src/components/PortExplorer.trust.test.tsx
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 4cb144a..3a8798d 100644
--- a/frontend/src/components/PortExplorer.tsx
+++ b/frontend/src/components/PortExplorer.tsx
@@ -70,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})` : ''}
+
@@ -122,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}
+ )}
)}
@@ -135,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
+ {typeof selectedPort.walkingTimeMin === 'number' && selectedPort.walkingTimeMin > 0
? (isGerman ? `ca. ${selectedPort.walkingTimeMin} Min. Gehzeit` : `approx. ${selectedPort.walkingTimeMin} min walk`)
- : (isGerman ? 'Shuttle-Transfer oder Taxi empfohlen' : 'Shuttle transfer or taxi recommended')}
+ : (isGerman ? 'Gehzeit unbekannt' : 'Walking time unknown')}
)}
@@ -150,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.'}
+
+ )}
@@ -209,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/ports.ts b/frontend/src/ports.ts
index bb03860..038d7fe 100644
--- a/frontend/src/ports.ts
+++ b/frontend/src/ports.ts
@@ -14,19 +14,21 @@ export interface CuratedPort {
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 | null;
- transitNoteEn: string;
- transitNoteDe: string;
- airportTransitEn: string;
- airportTransitDe: string;
+ transitNoteEn: string | null;
+ transitNoteDe: string | null;
+ airportTransitEn: string | null;
+ airportTransitDe: string | null;
currency: string | null;
cardAcceptancePct: number | null;
- emergencyPhone: string;
- policePhone: string;
+ emergencyPhone: string | null;
+ policePhone: string | null;
callingShips: { slug: string; name: string }[];
timEssentialsDe: string[];
timEssentialsEn: string[];
@@ -55,8 +57,8 @@ const CURATED_PORT_STORIES: Record
Date: Tue, 25 Aug 2026 00:16:46 +0200
Subject: [PATCH 5/5] test: make the compiler sandbox work without symlink
privilege
The sandbox added alongside the port quarantine exposed the real corpus to
KnowledgeDBCompiler via a symlink. That is not portable: on Windows
os.symlink needs SeCreateSymbolicLinkPrivilege, which an ordinary account
without Developer Mode does not hold, so the call fails with WinError 1314
and takes 13 tests with it -- 5 in test_cruise_intelligence_db, 4 in
test_live_fleet_operations, 3 in test_source_network, and the compiler
tolerance test that inlined the same call. CI runs on ubuntu-latest and
would not have caught it.
expose_knowledge() now links where it can and copies the corpus where it
cannot, and both call sites use it. Copying rather than skipping is the
point: these tests exist to exercise the real corpus, and skipping them on
the platform this repository is developed on would drop the coverage exactly
where a regression shows up first. The corpus is ~2 MB across ~450 files, so
the copy costs little. FileExistsError is deliberately not caught -- an
already-populated root is a caller bug, not a platform limitation.
The compiler only reads the corpus, so knowledge/ is untouched in both modes
and the guarantee the sandbox exists for is unchanged: no test writes into
data/ or knowledge/.
Backend goes from 931 passed / 6 failed / 7 errors to 944 passed on Windows.
No production code is touched, and the reviewed 0001-0004 series is unchanged.
Co-Authored-By: Claude Opus 5
---
tests/compiler_sandbox.py | 46 ++++++++++++++++++++++----
tests/test_port_identity_quarantine.py | 15 ++++++---
2 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/tests/compiler_sandbox.py b/tests/compiler_sandbox.py
index 4bdd901..51ed275 100644
--- a/tests/compiler_sandbox.py
+++ b/tests/compiler_sandbox.py
@@ -10,21 +10,55 @@
— 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 whose `knowledge` is a symlink
-to the real corpus. 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.
+`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.
@@ -36,7 +70,7 @@ def sandbox_root(cleanup_registry=None) -> str:
"""
handle = tempfile.TemporaryDirectory(prefix="timonelo-compile-")
root = pathlib.Path(handle.name)
- (root / "knowledge").symlink_to(REPO_ROOT / "knowledge")
+ expose_knowledge(root)
if cleanup_registry is not None:
cleanup_registry.append(handle)
else:
diff --git a/tests/test_port_identity_quarantine.py b/tests/test_port_identity_quarantine.py
index 0ab4097..60f89f3 100644
--- a/tests/test_port_identity_quarantine.py
+++ b/tests/test_port_identity_quarantine.py
@@ -424,19 +424,24 @@ def test_compiler_tolerates_unknown_values(tmp_path):
`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 whose `knowledge` is a symlink to the real corpus: 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.
+ 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"))
}
- (tmp_path / "knowledge").symlink_to(REPO_ROOT / "knowledge")
+ expose_knowledge(tmp_path)
compiler = KnowledgeDBCompiler(root_dir=str(tmp_path))
compiler.compile()