Adapter Capability Catalog¶
This is NOT the function library. It catalogs integration capabilities — what an adapter must DO end-to-end with the device or system (establish encrypted comms, sync time, manage credentials, run incremental vs full sync, APB, deliver events…).
For the device-side Thing functions (
Door,Reader,Partition,IntrusionDetector…) — the capabilities a Thing implements — seefunctions-registry.md.An entry here names the integration task and the framework primitive that backs it. The primitive (a function, command family, or event family) is the mechanism; the catalog entry is the job we expect the adapter to perform. Do not collapse the two axes.
Why this catalog exists¶
One way to survey a protocol is inductively — "enumerate EVERYTHING the protocol contains." That approach stays: it is the only way to catch vendor-specific capabilities a catalog can't predict.
This catalog adds the opposite, directed pass. For each capability we expect from an adapter of a given domain, walk the protocol and ask "is it here?" The catalog's unique value is surfacing expected capabilities that are ABSENT — an inductive enumeration structurally cannot do this (you cannot enumerate an absence). The two passes are complementary; the directed walk makes the search more targeted, not narrower.
How to use it¶
Run the directed walk after the inductive enumeration. For each catalog capability in the adapter's in-scope domain(s), assign exactly one classification:
| Classification | Meaning | Action |
|---|---|---|
present + mapped |
protocol has it; a framework primitive expresses it | implement / plan it |
present + unmapped |
protocol has it; no clean framework primitive | gap (no_framework_mapping, classification needs_framework_decision) → record, resolve with the team at the build CHECKPOINT |
absent |
protocol lacks an expected capability | gap (needs_vendor/needs_hardware) or out_of_scope with reason |
framework-unsupported |
framework cannot express it yet | gap (classification needs_framework_decision) → team decision at CHECKPOINT (extend framework / adapter-local workaround / defer); only a recorded decision may land as not supported by framework (DoD final state) |
A capability marked absent or framework-unsupported is still a deliverable observation — it
tells the partner what this device cannot do, and it tells us what the framework is missing. Never
drop it silently.
Backing primitives are verified against the framework's functions, pq-commands, and pq-events definitions.
Cross-cutting capabilities — evaluate for every adapter¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Connection & session | connect, authenticate, establish the (encrypted) channel, bind/register/login a session | transport layer + ConnectionBase; connection.* lifecycle events |
Is framing, auth, encryption, and session establishment documented? |
| Liveness / keepalive | heartbeat / watchdog / keepalive; detect a dead link | ConnectionBase, Comm; connection.degraded |
Does the protocol require or expose keepalive? What timeout declares the link dead? |
| Time synchronization | read and/or write the device clock; timezone; periodic resync | TimeSynchronization |
Is the clock readable/writable? What format/timezone handling? |
| Offline audit recovery | recover every audited event that occurred while we were not connected — treat an initial connect as one long outage; dedup and sequence/loss recovery so no audited event is lost across a disconnection | device-side event buffer / history readout (e.g. HistoryPoll); sequence/ack fields |
Does the device retain events while we are disconnected, and how are they read back without loss or duplication? |
| Health & supervision | report online/offline/degraded, tamper, power/battery, supervision fault, output-circuit overload and fuse state | Comm, Tamper, Power; technical.* / system.* / energy.power.* events (energy.power.overload[.restored] for a circuit drawing too much current, energy.power.fuse.* for the component itself) |
Which liveness and fault signals does the protocol expose? Does it supervise output current separately from fuses? |
| Configuration & reset audit | record what happens to the device's own configuration: an operator change, a restore of a stored configuration, and each destructive reset | system.configuration.changed / .restored, system.reset.factory / .settings / .database events |
Does the protocol report configuration restores and resets, and does it distinguish a settings reset from a full factory reset? |
| Configuration discovery | read the device's existing configuration (doors, readers, zones, points) and import it into PQ to populate the Thing tree — instead of modelling everything by hand; re-import reconciles against stored data per the discovery import contract (tri-state deviceRefs, name preserve, dangling-ref cleanup) | pq.command.config.import |
Can the device's current configuration be read back and imported? |
Access control domain¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Credential management | per credential type (card / PIN / biometric template / mobile) support the subtasks: enumerate, add, update, delete (plus batch / bulk-load where the protocol offers it) | AccessSynchronization + access-model.yaml; credential TPH (PersonCard / Pin / Biometric / OAuth) |
Which credential types are stored device-side? Which operations per type? |
| Card formats | encode/decode the card formats (Wiegand bit lengths, facility code, raw) the device accepts | access-model.yaml properties |
Which card formats? Facility-code handling? Bit layout documented? |
| Sync mode | distinguish incremental (update a single record in place) vs full-only (wipe + reload); pick the framework path accordingly | AccessSynchronization, access-model updatable: inplace; pq.command.access.synchronize |
Can the device update one record, or only accept a full dataset reload? |
| Reset & restore | wipe device tables and re-push a fresh dataset; restore after a panel wipe | pq.command.access.synchronize.reset |
Is there a clear-all? What does the device retain after a reset? |
| Double-sync safety | running sync twice with unchanged input must not throw or duplicate device state | AccessSynchronization |
(implementation gate — verify, not protocol-derived) |
| Schedules / time profiles | sync time schedules / day templates the device enforces | access-model entities |
Are schedules stored on the device? Structure and limits? |
| Access levels / groups | sync access-level / door-group / area bindings; model each authorizable unit (door and partition/area/floor) as an access_point: true Thing so the grant flows through person.Devices (see MODEL-002), not a static mask |
access-model entities |
How does the device bind credentials → doors / areas/partitions / levels? |
| Holidays | sync holiday calendars that modify schedule behaviour | access-model entities |
Holiday calendar support and structure? |
| Antipassback | sync APB zones; directional; clear/reset APB state | AntipassbackSynchronization; pq.command.access.synchronize.antipassback, pq.command.access.antipassback.clear |
Does the device enforce APB? Zone model? Reset path? |
| Door control | distinguish strike release (open/open.permanent + Unsecured*) from deadbolt/lock actuator control (lock/unlock + Locked*/Unlocked*); lockdown |
Door; pq.command.access.open, .open.permanent, .lock, .unlock; pq.command.emergency.lockdown[.cancel] |
Which door operations does the protocol expose? Is it a strike/relay release or an actual lock/deadbolt state? |
| Reader mode / enable | enable/disable a reader; switch reader/schedule mode (day/night/T2) | Reader; pq.command.access.disable/.enable, pq.command.schedule.mode.day/.night/pq.command.schedule.switch.t2 |
Can reader mode be commanded remotely? |
| Access events | route grant, deny, unknown-credential, forced, held, REX | Door, Reader; access.* event family |
Which access events fire? Do they carry credential identity? |
| Enrollment | live capture per type — card / PIN / face / fingerprint template — with failure behaviour, cancellation, and cleanup of partial captures | pq.command.access.enroll.card, .enroll.face (extend per protocol for other template types) |
Which template types can be captured live? Failure/timeout and cancellation semantics? Is a partial capture cleaned up? |
Intrusion domain¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Arm / disarm | arm (away/forced/partial/stay/sleep) and disarm partitions | Partition, SecurityKeypad; pq.command.security.arm[.forced/.partial/.stay/.sleep], .disarm |
Which arm modes exist? Per-partition or system-wide? |
| Bypass | bypass and remove-bypass zones | pq.command.security.bypass, .bypass.cancel |
Can zones be bypassed remotely? |
| Alarm reset | acknowledge / reset alarm state | pq.command.security.alarm.reset |
Reset path and conditions? |
| Partitions / zones | model partitions/areas and their member zones | Partition, IntrusionDetector |
Partition↔zone topology and limits? |
| Alarms / tampers / troubles / restores | route the full event taxonomy, including restores | intrusion.* event family; Tamper |
Which alarm/trouble/restore events fire? |
| User-code management | intrusion user codes are credentials (PIN) — sync them via Access › Credential management; model here only the intrusion-specific semantics a code adds (arm-only / duress / ack). A panel with full user management is also an ACS, so this is then already satisfied there. | AccessSynchronization / access-model |
Does the panel add intrusion-specific code semantics beyond a plain credential? |
| Entry / exit delay | represent entry/exit delay states | Partition states |
Delay semantics documented? |
| Sounder / alarm control | mute/activate sounders and buzzers; start/finish alarm-test mode | pq.command.alarm.* (.mute.sounder / .mute.buzzer / .activate / .test.start / .test.finish) |
Can sounders be muted or alarm-tested remotely? |
Fire domain¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Fire panel state | model the EPS/FACP panel, summary alarm/trouble state, acknowledge/reset, day/night mode, service/configuration access, and test lifecycle | FirePanel; fire.panel.*, fire.alarm.*, fire.trouble, fire.test |
Does the protocol expose panel-level events separately from point events? |
| Fire detection & address state | display fire detectors / zones / addresses in their states; route all fire events the protocol defines (alarm, pre-alarm, smoke, heat, manual call-point, suppression, supervisory, cleared, disabled, test, trouble) | FireDetector, FirePoint; fire.* event family; detector states |
Which detector/address types and states exist? Which fire events fire? |
| Fire signaling outputs | model sounders, fire routing/transmission, and fire-control outputs as separate Things when the protocol exposes them | FireSounder, FireRouting, FireControlOutput |
Are sounders, ZDP/OPPO/routing, or fire-control outputs addressable? |
| Fire system control | command the fire-system controls the protocol exposes — routing / protection / sounder delays, sounder mute/reactivate, test start/finish | pq.command.fire.*, pq.command.alarm.* |
Does the protocol expose any fire control, or is it observe-only? |
Safety & emergency domain¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Panic / duress / emergency | route the panic (fire / medical / police), duress, medical, evacuation and lockdown signals the protocol defines | safety.* event family; pq.command.emergency.evacuation[.cancel], pq.command.emergency.lockdown[.cancel] |
Which panic/duress/emergency signals exist? Is there a silent-duress credential? |
Video domain¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Channel discovery | enumerate channels and online/offline status | StatusPoll; video.* events |
How are channels enumerated? |
| Live / playback / snapshot | start live, control playback, take snapshots | pq.command.video.live, .playback[.pause/.resume/.seek/.speed/.step], .snapshot |
Which streaming/playback operations are exposed? |
| PTZ / presets | move/stop PTZ; activate/store presets | pq.command.camera.ptz.move/.stop, .preset.activate/.store |
PTZ control and preset model? |
| Analytics | route video-analytics events (motion, line-cross, object, tamper) the device emits | video.* event family |
Which analytics events does the device emit? |
| Faults & teardown | recording/storage faults; stream teardown and reconnect ownership | video.* / technical.* events |
Fault signals? Who owns stream teardown? |
I/O domain¶
| Capability | What the adapter must do | Backing primitive | Protocol question |
|---|---|---|---|
| Inputs | monitored input points; supervision; NO/NC; fault (read-only — state arrives as events) | Input; technical.* / domain events |
Supervision and NO/NC semantics? |
| Outputs | activate / deactivate; pulse / timer; report state | Output; pq.command.output.activate/.deactivate, pq.command.on/.off/.reset |
Which output operations and timing modes? |
| Output schedules | scheduled output behaviour | Output + schedule data |
Scheduled outputs supported? |
Gateway / native-SDK adapters — cross-cutting addendum¶
Applies on top of the domain above when the adapter wraps an external process or native library.
| Capability | What the adapter must do | Reference |
|---|---|---|
| External lifecycle | start/stop the native lib or sidecar process; handle startup failure | archetypes/native-sdk-shared-transport.md, archetypes/gateway-grpc.md |
| Shared transport | multiplex many Things over one SDK connection without holding Thing refs across async | framework Thing memory-safety rules |
| Platform limits / SDK errors | translate SDK error codes; document platform constraints | archetype docs |
Out of catalog scope¶
The framework can carry these event families, but they are building-automation, not PACS adapter
capabilities, so the directed walk does not evaluate them: hvac.*, utility.* (elevator / gas /
water), energy.* consumption (note: energy.power.* is in scope — see Health & supervision), and
notification.* (server-side outbound). An adapter that happens to surface one of these records it as
a vendor-specific extra, not a catalog gap.
See also¶
functions-registry.md— the device-side Thing function library (the other axis)../definition-of-done.md— the completion gates; its capability section points here../archetypes/— transport/integration shapes (how the adapter talks)../modeling-conventions.md— structural conventions for the Thing tree