The test suite
85 tests across five groups. Every test names the clause it enforces and the exact condition that constitutes a pass. A conformance statement MUST list the tests it fails.
PK — Package validity 28 tests · target: package
Procedure. Open the package as a ZIP archive.
Pass. The archive opens, the first entry is named 'mimetype', it is stored uncompressed, and its content is exactly the registered media type string with no trailing newline.
Procedure. Read manifest.json at the package root and validate against bus-manifest.schema.json.
Pass. The manifest exists and validates with no errors.
Procedure. Validate every file listed in manifest.documents against bus-document.schema.json.
Pass. Every listed document exists and validates with no errors.
Procedure. Recompute the digest of every entry in manifest.documents and manifest.resources.
Pass. Every recomputed digest equals the declared digest, and every declared byteLength matches.
Procedure. Enumerate all archive entries.
Pass. Every entry other than 'mimetype' and 'manifest.json' appears in manifest.documents or manifest.resources.
Procedure. Inspect every archive entry name.
Pass. No entry is absolute, contains a '..' segment, or resolves outside the package root.
Procedure. Collect every entity id in the package.
Pass. No id occurs twice.
Procedure. Resolve every reference in the package: relationship subject and object, deviceRef, networkRef, targetOf, appliesToRef, scheduleRef, deployment.controllerRef, port mapsTo.assetRef, ChangeRecord subject, and every other IdRef-typed field defined by the core schema. Derive the field list from the schema rather than from this sentence: v0.3 added three reference fields that a hand-maintained list did not catch.
Pass. Every reference resolves to an entity present in the package, or to an entity explicitly declared external in the manifest.
Procedure. Collect every namespace prefix used in type names, predicates and extension keys.
Pass. Every non-bus prefix is declared in manifest.extensions.
Procedure. Inspect manifest.completeness.domains.
Pass. All twelve substrate domains are present, and every domain in state partial or absent carries a reason.
Procedure. Compare the declared profile against the domains actually populated.
Pass. Every domain required by the declared profile is in state complete or partial, not absent.
Procedure. Collect every property value in the package and resolve its definition.
Pass. Every property value references a bus:PropertyDefinition present in the package. No bare key-value property data appears anywhere.
Procedure. For each property value, compare its shape against the declared datatype and unit.
Pass. Quantity values carry the unit declared by the definition; string, number and enum values match their declared datatype.
Procedure. Resolve every element drawing and layer, every layer drawing, every represents and navigatesTo, and every binding element and target.
Pass. All resolve. Every element's layer belongs to the same drawing as the element. Every navigatesTo names a drawing.
Procedure. Count write and readWrite bindings and compare against manifest.actuation.
Pass. present matches whether any write binding exists; bindingCount and highestPriority match the content. A package containing write bindings and declaring actuation absent fails.
Procedure. For each write binding, inspect its write block and its target.
Pass. A command priority is declared, the target point is writable, the priority is within the target's declared priority model, and any constraintRef or interlockRef resolves to a bus:Constraint.
Procedure. Inspect each drawing for a reference dimension.
Pass. A reference dimension is present and its stated length agrees with the distance between its two drawing coordinates under the declared units.
Procedure. For every bus:Asset carrying ports, compare the port names in the array.
Pass. No asset declares two ports with the same name. JSON Schema cannot express uniqueness over a field of an array item, so this is the only check that enforces it — and PK-21 is undecidable without it, because a subjectPort could match two ports at once. Note that direction and medium are required by the schema and therefore already graded by PK-3.
Procedure. For every port carrying pairedWith or mapsTo, resolve the target.
Pass. pairedWith names another port on the same asset. mapsTo names an asset that exists in the package and a port that asset declares. An unresolvable pairing is reported, not repaired.
Procedure. For every relationship naming a port at either end, compare the relationship's medium with the medium of the named port.
Pass. They are equal. A relationship carrying chilled water into a port declared for air is reported: it is the signature of a mis-wired export and is invisible without ports.
Procedure. For every relationship carrying subjectPort or objectPort, look for a matching Port.name on the endpoint asset.
Pass. Every named port is declared by the asset at that end of the relationship. A port name matching nothing is a package error. Scoped per 18.3.1: the check applies to an endpoint that declares ports, so a v0.2 package — which cannot declare any — neither fails nor is exempted by special case.
Procedure. Parse every figure source. Compare its elements and attributes against bus-vector-profile.json.
Pass. Every figure is well-formed XML, declares a viewBox, contains no element outside the permitted list, contains no reference resolving outside the figure, carries no CSS, and is within the nesting and element ceilings of VEC-5. Scoped per 18.3.1: a package declaring busVersion 0.2 is not graded on a profile that did not exist when it was written. A receiver still refuses to render a figure that violates 19.3, which is a rendering refusal and not a package refusal.
Procedure. For every TelemetryBinding carrying networkRef, resolve it.
Pass. It names a bus:Network in the package. A binding pointing at a network the package does not contain is reported.
Procedure. Compare every protocol token against bus-protocols.json.
Pass. A token that matches a registered token case-insensitively but not exactly is reported — 'BACnet/IP' where 'bacnet' is registered. An unregistered token is NOT a failure: the registry is open and an unknown protocol MUST be preserved.
Procedure. For every bus:Sequence, look for a deployment block.
Pass. The block is present and its state is asDesigned, asDeployed or unknown. Absence is reported: it is the case where a reader cannot tell whether they are looking at the submittal or at what the controller runs.
Procedure. For every bus:Sequence carrying deployment.controllerRef, resolve it.
Pass. It names an entity in the package. PK-8 enumerates the reference fields it closes over and was not extended when this field was added, so without this check a sequence could name a controller that does not exist and pass the suite.
Procedure. For every georeference carrying the v0.3 affine form: compute the determinant of its linear part (a*e - b*d); where the anchor fields are also present, apply the affine to (atX, atY) and compare against the anchor's position, and compare the affine's rotation against the declared rotation.
Pass. The determinant is nonzero, every coefficient is finite, and where both forms are present they describe the same placement within the RT-18 tolerance. A singular transform maps the whole drawing onto a line, and two forms that disagree are a package contradicting itself — both package-visible, neither a matter of exporter knowledge. Applies only where the affine is present; both forms are OPTIONAL and an exporter that does not know a transform omits it (13.3).
Procedure. For every signature present in the manifest's signatures slot, parse the envelope.
Pass. It is a structurally valid detached JWS or CMS envelope and it covers the manifest bytes. Cryptographic verification is out of scope for a package test — the receiver holds no keys — but an envelope that does not parse, or that covers something other than the manifest, is decoration wearing a signature's clothes, and is reported. Absence of any signature is NOT a failure; 19.2-1 grades signing SHOULD.
RT — Round-trip reconstruction 28 tests · target: roundTrip
Procedure. Compare the id of every entity in A with its counterpart in B.
Pass. Every id in A appears unchanged in B, or B contains a bus:IdentityMapping with equivalence 'same' linking the new id to the original. No entity is silently reidentified.
Procedure. Compare type, pointKind, dataType, unit, range, enumeration, classifications and attributes for every entity.
Pass. All are preserved. Unit codes are preserved without conversion, or converted with the original code recorded in provenance.
Procedure. Construct the labeled directed graph of relationships in A and in B and test for isomorphism under the identity mapping from RT-1.
Pass. The graphs are isomorphic, including predicate, direction, medium and qualifiers. Inverse-form substitution is permitted; loss of a relationship is not.
Procedure. For each Objective, Target, Constraint, Schedule and SequenceReference in A, locate it in B.
Pass. The receiving system can still distinguish what should happen from what is happening and what happened. Constraints retain their constraintKind and bounds; schedules retain their recurrence and exceptions.
Procedure. Compare provenance blocks and ChangeRecords.
Pass. assertedBy, assertedAt, method, source, confidence and approvals survive. The receiving system MAY add its own provenance; it MUST NOT overwrite the original.
Procedure. Include in A an extension namespace the receiving system does not implement, with mustUnderstand false, attached to at least one entity of each core class.
Pass. Every extension value reappears in B byte-identical after canonicalization, and the namespace is still declared in B's manifest.
Procedure. Include in A an extension with mustUnderstand true that the receiving system does not implement.
Pass. The importer reports the import as incomplete and names the namespace. It MUST NOT report success, and it MUST still preserve the data.
Procedure. Compare resource payloads and digests between A and B.
Pass. Included resources are byte-identical and digests match. Externally referenced resources retain their URI and digest.
Procedure. Compare the binding object of every point.
Pass. protocol, address, network and parameters are preserved verbatim, so acquisition can be re-established without rediscovery.
Procedure. Compare every KnowledgeNote and its attachment relationship.
Pass. Body text, noteKind, observedAt and the appliesTo relationship survive unaltered.
Procedure. In A, replace an asset and record bus:replaces and bus:replacedBy. Round-trip.
Pass. B retains both the superseded and the superseding entity and the replacement relationship, so history remains attributable across the change.
Procedure. Compare B's completeness declaration against what B actually contains, and against A.
Pass. Anything present in A but absent from B is declared in B's completeness block with a reason. Silent loss is a failure of this test even when every other test passes.
Procedure. Import B and re-export as C.
Pass. C and B are identical after canonicalization. Drift between successive round trips indicates unstable identity or unstable ordering.
Procedure. Round-trip a package with at least 50000 points and 250000 relationships.
Pass. Report wall-clock export time, import time and peak memory. No pass or fail threshold is set in v0.1.
Procedure. Compare every binding in A with its counterpart in B: element, target, channel, direction, mapping, quality.
Pass. All survive. A binding lost, repointed, or reduced to a different channel is a failure, even where the graphic still renders.
Procedure. Round-trip a write binding whose priority the receiving system does not natively support.
Pass. The priority is re-exported unchanged and the importer reported that it could not honor it. Silent substitution is a failure even though the graphic appears identical.
Procedure. Compare the quality block of every binding.
Pass. staleAfter, onStale, onUnavailable and onOutOfService survive unchanged.
Procedure. Compare drawing coordinate systems, extents, layer purposes, and every element geometry and transform.
Pass. Coordinates agree within one part in 10000 of the drawing extent. The coordinate system, georeference, and layer purposes are unchanged.
Procedure. Include an element whose leaf symbol role the receiving system does not implement but whose ancestor it does.
Pass. The receiver renders using the ancestor role and re-exports the original leaf role unchanged. Substituting the ancestor into the exported data is a failure.
Procedure. Round-trip an element carrying a figure payload for which no symbol role applies.
Pass. The figure survives byte-identical after canonicalization and is rendered substantially as given rather than replaced by a library symbol.
Procedure. Compare every property definition and every property value.
Pass. Definitions survive with their meaning text intact. No property is re-exported without its definition, and no definition is silently merged with another of the same name but different meaning.
Procedure. Compare every alarm definition: limits, deadband, delays, priority, acknowledgment, shelving and routing.
Pass. All survive. Routing that the receiver cannot execute is preserved and reported as unenforced, not dropped.
Procedure. Compare every event and its subject reference.
Pass. Event kind, timestamps, actor, values and subject survive. An override event that loses its subject is a failure.
Procedure. Compare the versioning block of every entity across the round-trip.
Pass. Revision numbers are preserved or advanced, never reset. An entity re-exported at revision 1 having arrived at revision 4 is a failure.
Procedure. Export, import, re-export. Compare ports on every asset.
Pass. Every port's name, direction and medium is unchanged, and every relationship still names the same ports. Reordering the array is permitted; renaming a port is not.
Procedure. Export, import, re-export. Compare bus:Network entities and the bindings referencing them.
Pass. Networks appear with the same identifier and protocol, and the same bindings reference them. Collapsing two networks into one is a failure even where every binding still resolves.
Procedure. Export, import, re-export a sequence whose deployment state is unknown.
Pass. The state is still unknown. A round trip that turns unknown into asDesigned has manufactured a claim about the building, which is the specific failure 10.5.1 names.
Procedure. Export, import, re-export a package carrying series. Compare every bus:Series and every sample file between A and B.
Pass. Each sample file reappears byte-identical — the format has no permitted variation, so byte equality is the comparison rule — and each bus:Series survives with pointRef, coverage, sampling, aggregation, unitCode and rowCount unchanged. An importer stores samples however it likes; what it re-emits is the same bytes.
IM — Importer behavior 11 tests · target: importer
Procedure. Present a package in which one document digest does not match.
Pass. The importer refuses the package and names the failing path. Partial silent ingestion is a failure.
Procedure. Present a package whose busVersion has a higher major number.
Pass. The importer refuses and reports the version it supports.
Procedure. Present a package whose busVersion has the same major and a higher minor number.
Pass. The importer accepts it, preserves what it does not understand, and reports which constructs it ignored.
Procedure. Present a package using an enumeration member added after the importer was built.
Pass. The importer preserves the value and does not coerce it to a default.
Procedure. Import a valid package.
Pass. The importer produces a machine-readable summary of entities ingested, entities preserved but not interpreted, and constructs not understood.
Procedure. Present an element with a symbol role several levels deeper than the importer implements.
Pass. The importer walks the dotted path upward, renders at the deepest ancestor it knows, and preserves the original role. Refusing the package or dropping the element is a failure.
Procedure. Present write bindings whose priority model, interlock, or confirmation requirement the importer cannot enforce.
Pass. Each is named in the import report as unenforced. Importing them as ordinary writes without report is a failure.
Procedure. Present a package containing a property value whose definition is absent.
Pass. The importer reports the package as invalid and names the property. Accepting it as an untyped string is a failure.
Procedure. Import a package whose TelemetryBinding carries a protocol token outside the registry, then re-export.
Pass. The token survives byte-for-byte. An importer that normalizes an unknown protocol to a known one, or drops the binding, has failed.
Procedure. Import a package declaring ports into a system with no port concept, then re-export.
Pass. The ports reappear, or the re-export declares the relevant domain partial with a reason. Silent loss is the failure this test exists for.
Procedure. Present a package containing a figure with a script element, a foreignObject, or an href resolving outside the figure.
Pass. The importer refuses the figure and says why. Silently stripping the offending element is a failure: the exporter is not told its package is invalid, and the next receiver may not strip it.
EX — Exporter behavior 11 tests · target: exporter
Procedure. Produce a package and inspect it for references that can only be resolved by the exporting vendor.
Pass. Every reference is either resolvable inside the package or is a durable external locator with a digest. No reference requires a proprietary service to interpret.
Procedure. Export the same building twice with no intervening change.
Pass. Every entity id is identical in both exports.
Procedure. Rename an asset, then export again.
Pass. The id is unchanged and the rename appears as a ChangeRecord.
Procedure. Compare the exported model against the model the system uses to operate the building.
Pass. No construct the system relies on to operate is omitted without a completeness declaration naming it.
Procedure. Attempt an export as an operator-role user without vendor assistance.
Pass. The export completes without vendor involvement, professional services, or a support ticket.
Procedure. Export a floor plan and an equipment graphic as an operator-role user.
Pass. Both export with geometry, roles and bindings intact, without vendor involvement or professional services. This is the test the rebuild tax is measured against.
Procedure. Export the same building twice and compare property definition identifiers.
Pass. Definition identifiers are stable between exports. Regenerating identifiers each time defeats RT-21 and makes cross-package comparison impossible.
Procedure. Export from a system that records connection topology but not port structure.
Pass. Ports are absent. An exporter that synthesizes port names to fill the field has asserted something nobody knows, which 5.3.5 exists to prevent.
Procedure. Export from a system holding both design sequences and running control programs, exporting only the former.
Pass. The manifest declares intent partial with reason notSupportedByExporter. An exporter that ships the submittal, declares intent complete, and leaves the running logic behind is technically conforming and materially false. Graded SHOULD despite the requirement being a MUST, because nothing in the package reveals what the exporting system also held: this is checked against the source system during certification, not by a receiver, and a receiver MUST NOT refuse on it.
Procedure. Export from a system whose historian is unreachable, retention-limited, or partially excluded by the owner.
Pass. The timeSeries domain is declared partial or absent with the reason that is true: sourceUnavailable for a store that could not be reached, retentionExpired for data the window has purged, excludedByOwner for an interval withheld on instruction. Graded SHOULD because nothing in the package reveals what the exporter's historian held; this is checked against the source system during certification, and a receiver MUST NOT refuse on it.
Procedure. Present concurrent updates for one entity from two systems to an exporter, then inspect what it emits.
Pass. Either one package whose revisions advanced under a single serialized writer, or two packages with distinct packageIds and the succession recorded per 16.9. One package advancing one revision counter under two authorities asserts an ordering nobody enforced, and fails. This test exists so that the single-writer assumption is a tested boundary rather than an escape hatch: an exporter cannot claim concurrency to exempt itself from the reconstruction tests, because handling concurrency correctly is itself the requirement.
TS — Time series 7 tests · target: package
Procedure. Parse every file a bus:Series names against the bus-csv-1 grammar: encoding, line endings, the exact header, timestamp form and ordering, the value grammar, the quality vocabulary.
Pass. Every file parses with no violations. UTF-8 without a byte order mark, LF line endings, the header row exactly 'timestamp,value,quality', RFC 3339 UTC timestamps with the Z designator in non-decreasing order, values within the grammar for the point's dataType, quality tokens from the fixed vocabulary or empty, and the value field empty exactly where quality is missing.
Procedure. For every bus:Series, resolve pointRef against the package's entities and resourceRef against manifest.resources and the archive.
Pass. pointRef names a bus:Point in the package. resourceRef names a manifest resource whose path exists in the archive, so its digest was verified by PK-4 before any row was read. A series naming a point or a file the package does not contain is a package error.
Procedure. Count the data rows of every sample file and compare with the declaring series.
Pass. Series.rowCount equals the rows in the file, excluding the header. A mismatch is the signature of a truncated or padded export, and the declared count is what makes it detectable — the same mechanism as the actuation declaration (PK-15).
Procedure. Compare the first and last timestamps of every sample file with the declaring series' coverage interval.
Pass. Every row's timestamp lies within [coverage.start, coverage.end]. Coverage MAY be wider than the data — an exported period that held no samples — and MUST NOT be narrower.
Procedure. For every series whose point carries a unitCode, resolve both codes against the quantity families of bus-units.json.
Pass. The series unit and the point unit name the same quantity. A series in kPa on a temperature point is a mis-wired export, visible to any receiver, and stating the unit in both places is what makes it detectable.
Procedure. For every series whose point carries a unitCode, compare the two codes for equality.
Pass. They are equal. Where they differ, the samples are in the series' unit, the disagreement is a true fact about the source system — a historian that kept degF after the point was re-configured to degC — and it is reported, never repaired by conversion (BUS-1 7.4-1). Graded SHOULD because a true statement about the source is not a contradiction in the package.
Procedure. Where the timeSeries domain is declared complete, compare each point's history declaration (BUS-1 8.8) with the series that carry it.
Pass. Every point declaring history available has at least one series, and the union of its series' coverage encloses the declared from/to extent. Both statements are the exporter's own, in one package; a package that declares completeness its own point declarations contradict is internally inconsistent, which is what MUST grades. A domain declared partial or absent is not graded here.
Machine-readable: bus-conformance-tests.json