Coastal Shipping 11 — Port & Terminal Electronic Interface (coast_11_portinterface)

Tell the port authority what the ship carries, and keep what the authority actually answered apart from whether the message got there — electronic manifest submissions, every transmission attempt, the authority's acknowledgments, corrections that amend an accepted submission without erasing it, terminal notices (external observations), reconciliation and deadlines.

Its central question:

The manifest was sent to the port — did the authority actually accept it, for this revision, and can we prove which cargo it accepted?

coast_11_portinterface is application SHP-11 of the Coastal Shipping series (coast_NN_<name>, numbered by the pack catalogue; each able to run stand-alone or as a network member, Stage 3). It shares no tables and no foreign keys with its siblings (for example coast_02_manifest, whose effective cargo it submits, or coast_06_voyage, whose port calls it names) — they link by canonical_ref strings and by messages. All data is fictional.

THE TRANSMISSION ADAPTER IS A SIMULATION. There is no real port, terminal or authority, no wire format, no endpoint, no credential and no authority schema anywhere in this application. A profile carries a mode (SIMULATION), a schema label (mock_fixture_only) and, for a live profile that does not exist, a secret-store reference. A simulated acceptance is stored as simulated, published as mode SIMULATION, and confers nothing real: it cannot authorise a release, a sailing or a clearance.

The spine

PortInterfaceAuthority → PortInterfaceProfile → PortSubmission → SubmissionCargo / TransmissionAttempt / PortAcknowledgment / PortCorrection, with TerminalNotice, PortInterfaceReconciliation, TransmissionDeadline, PortInterfaceException, PortInterfaceAudit and PortInterfaceSnapshot around it.

The documents

Page What's in it
00 — Overview What the app is, transport vs acceptance, the rules, the 13 models, the demo scenario
01 — Quick Reference Menu map, every model, status vocabularies, the messages, how to run, seed and regenerate
02 — System Diagram The data model as diagrams (+ interactive viewer) and how the app links to its siblings

Status

Built (handlers and workflow, tested): profile verification and activation (a LIVE profile is refused unless verified by one person, authorised by another and given a secret-store reference; none can be sent in this build); a submission prepared from the positive effective cargo of the manifest (never a reversal row; a DRAFT is prepared automatically when a manifest's effective cargo first arrives, if the profile's auto_prepare asks for it, and corrections are proposed with a replacement DRAFT when a newer revision arrives - nothing is ever sent without a person), validated against the current revision, the profile in force and the named load port call, approved by a supervisor who did not prepare it, sent through the simulated adapter (deadline checked, a late send needs a reason, no duplicate declaration, no resend while uncertain); the authority's response recorded apart from the transport result (accepted, rejected, partial and uncertain are different things; a conflicting, unauthentic, mismatching or unsolicited response is quarantined); corrections that keep the original, its attempts and its responses until the replacement is accepted; terminal notices as observations (validated, quarantined, never changing a movement or a tally); reconciliation with evidence by someone other than the sender; exceptions that close only when the domain correction is real; append-only attempts, responses and audit.

Scheduled (built, tested): portinterface.sweep_deadlines marks an overdue deadline and raises one exception, and makes a sent submission with no response in time UNCERTAIN (never resent).

Simulated, not real: transmission, authority responses, terminal notices, authenticity checks and the payload store (simulation-store:... labels, not stores). Not built: any live adapter, any real wire format or schema, signatures or replay protection of a real authority, real deadline rules.

Not enforced yet: the pack's "deadline per authority rule" is a date on a row (rule_version is a label); the call-completion obligation in coast_06_voyage (a call completes only with an accepted transmission) is that application's to enforce from the portinterface.submission_status event; assurance verification of closure is coast_16_assurance's. The rules are in integration/rules.py, integration/exceptions.py, integration/engine.py and integration/handlers.py; the simulated adapter is integration/simulation.py; their tests are under server/tests/integration_apps/test_coast_11_*.

Translation decisions (pack → native DSL)

  • 14 pack models: 12 translated, 2 dropped (S812 OutboxEvent, S813 InboxMessage: the integration runtime provides them), 1 added (PortInterfaceException, the app's own control exception, as ReleaseException) = 13.
  • Fleet-unique names: PortInterfaceAuthority, PortInterfaceProfile, PortInterfaceReconciliation, PortInterfaceAudit, PortInterfaceSnapshot (pack ExternalAuthority, InterfaceProfile, InterfaceReconciliation, Audit, ExternalSnapshot); the rest keep the pack's names.
  • canonical_id → canonical_ref; cid on the three network entities (PortSubmission, TerminalNotice, PortInterfaceException); version → version_no; source_event_id → source_event_sid; the pack's voyage_ref, port_call_ref, manifest_ref become *_canonical_ref + *_cid + *_ref (readable); dates are DateTime; name added to FK targets; enums upper case from the pack workflows (DRAFT … SUPERSEDED, RECEIVED, VALIDATED, QUARANTINED).
  • Added fields: mode, the validating / approving / sending people and times, late_send_reason, simulated_transport_result (SIMULATION profiles only), approved_payload_hash on PortSubmission; status, authenticity, simulated, reported_ack_key on PortAcknowledgment; notice_no, authenticity, simulated, reported_notice_key, quarantine_reason on TerminalNotice; live_enabled, credential_ref, ack_timeout_minutes, auto_prepare, verification and live-authorisation people on the profile; resolved_by / resolved_at on reconciliation. The pack's unique external_ack_key / external_notice_key are kept: a conflicting repeat is stored under <key>~conflict~<hash8> with the key as sent in reported_*_key.
  • Event names: shipping.portinterface.submission_status.v1 → portinterface.submission_status, …terminal_notice.v1 → portinterface.terminal_notice; the generic control.exception_detected / assurance.action_completed → portinterface.exception_raised / portinterface.exception_resolved. submission_kind is the submission's message_kind in the event payload and observed_at the notice's occurred_at, because those are envelope field names.
  • The pack gives SHP-11 no command; portinterface.sweep_deadlines (orchestrator, scheduled) is added, as release.sweep_expired was.
  • The pack's submission_status is published only for ACCEPTED, REJECTED, UNCERTAIN, SUPERSEDED (the pack: "verified authority response only; transport sent is not acceptance"): SENT is never published.
  • A partial acknowledgment is not an acceptance: it rejects the submission as sent (status REJECTED, exception PARTIAL_ACKNOWLEDGMENT, reconciliation PARTIAL_ACK); a definite "not delivered" transport result is not simulated (a failed or unknown send is UNCERTAIN: the conservative reading of "reconcile before resubmitting").
  • The notice quarantine exception has no control code (the pack's only SHP-11 control is PORT_SUBMISSION_UNCONFIRMED, for submissions).

Prototype system; draft. All names and data are fictional. Simulation only.