Wiring#

The plan that decides which connector is attached to which field.

Recognition and wiring: turn a resource’s ClassSpec into connector registrations.

This is the step that registers from the knowledge graph. It runs at construction, not during on_start_up. The reason is sharp. lifespan calls connect() on everything in the connection registry before it runs on_start_up callbacks. initiate_sync (what add_synced_connector defers) starts run_receive(), but never calls connect(). A connector registered while the datamodel materializes therefore never connects. The client stays None. The listener task never starts. Its queue is never fed. receive() blocks forever. Outbound would limp along, because consume() reconnects on failure. The failure is one-directional and silent.

Register at construction instead. This avoids the failure, with no out-of-band lifecycle call. It is possible because everything a ConnectionInfo needs comes from the ClassSpec and the graph.

Two shapes come out of here. Both are required.

  • The full spec. The bindings read it to find broker addresses and topics.

  • The pruned spec. The system serves this northbound.

kapps_semantic_middleware.connectors.wiring.EXPLICIT_GRAPH = 'FROM <http://www.ontotext.com/explicit>'#

Restrict a query to asserted triples.

It is not an ontology term, so it does not belong in vocabulary.py. It names a GraphDB feature, the pseudo-graph of explicit statements. It is a constant rather than three inline copies because every recognition query needs it for the same reason. The default graph includes materialized inference, and a parameter node’s only types are anonymous restriction nodes that exist by inference alone. Count or read without this. This returns inferred triples and inflates every result.

class kapps_semantic_middleware.connectors.wiring.WiringPlan(northbound_spec: Any, class_scope: Any, bindings: List[ParameterBinding], registrations: List[Tuple[ParameterBinding, Registration]], southbound_properties: frozenset, southbound_by_property: Dict[str, frozenset])[source]#

Bases: object

This describes what recognition found, and what the caller should do about it.

northbound_spec: Any#

The pruned ClassSpec, safe to materialize and serve.

class_scope: Any#

The scope where the system resolves the specs.

Keep this because a fetch needs both. _fetch_object_property decides whether a nested individual is hydrated or fetched as a bare reference from the class_scope (as_reference = nested_class_scope is None), not from whether the spec it was handed has a nested. Passing only the pruned spec yields belts and barriers with empty parameters. Use northbound_fetch_kwargs() rather than restate this.

bindings: List[ParameterBinding]#

This lists every recognized interface-accessible parameter. Populate for every flavour, including one that wires nothing. The system never gates recognition.

registrations: List[Tuple[ParameterBinding, Registration]]#

The connector registrations to perform. Empty when the flavour wires nothing.

southbound_properties: frozenset#

The prune set that was applied, kept for assertions and diagnostics.

southbound_by_property: Dict[str, frozenset]#

The same prune set, broken out per recognized parameter property rather than unioned across all of them. plan_wiring already computes this as a cache (southbound_by_property, one ontology round trip per distinct property rather than one per binding) and used to discard it once southbound_properties was built. Kept here instead: a consumer that shows what pruning stripped per parameter – the demo’s station board – needs exactly this breakdown, and recomputing it a second time would cost the same ontology queries this cache exists to avoid paying twice.

northbound_fetch_kwargs() → Dict[str, Any][source]#

The arguments that materialize this resource’s northbound view.

kapps_semantic_middleware.connectors.wiring.plan_wiring(*, ogm: Any, resource_iri: IRI, class_scope: Any, resource_class: IRI | None = None, registry: SemanticConnectorRegistry, flavour: SyncDirection = SyncDirection.BIDIRECTIONAL, autoregister: bool = True, ensure_transport: Callable[[str, int], None] | None = None) → WiringPlan[source]#

Resolve a resource’s parameters and decide what to connect.

autoregister gates only the registrations. Produce the spec, the projection, and the recognized bindings either way. An inspecting instance that skipped recognition would treat every parameter node as ordinary data, and serve its broker address. The least-privileged connector wiring would leak the most.

ensure_transport is the deployment’s transport hook. Wrapped once here, fresh per call, so it fires at most once per distinct (host, port) across every binding built below – a binding descriptor calls it unconditionally and the wrapper absorbs the dedup, so no descriptor has to track addresses it has already seen across calls it cannot see each other from.

kapps_semantic_middleware.connectors.wiring.class_of(ogm: Any, instance_iri: IRI) → IRI[source]#

Return the individual’s asserted domain class, so a caller need not restate it.

An individual carries several rdf:type assertions, and their order means nothing. So this filters out the structural types rather than trusting them to sort last. owl:NamedIndividual is the trap: it is asserted on everything the OGM writes, and a ClassSpec resolved against it cannot resolve at all.

Public because a consumer that discovers resources in the graph needs exactly this answer, and the alternative is the copy that grew in the demo’s station board and drifted.