{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "busVersion": "0.2",
  "title": "BUS-1 v0.2 Conformance Test Suite Outline",
  "status": "This outline is normative as to what MUST be tested. Fixtures and a reference runner are deferred to the reference tooling release.",
  "targets": {
    "exporter": "A system that produces an exchange package.",
    "importer": "A system that consumes an exchange package.",
    "package": "A single artifact, tested statically without either system present.",
    "roundTrip": "An exporter and an importer tested as a pair: export, import, re-export, compare."
  },
  "profiles": {
    "core": [
      "identity",
      "spaces",
      "assets",
      "points",
      "relationships",
      "resources",
      "provenance"
    ],
    "core-intent": [
      "identity",
      "spaces",
      "assets",
      "points",
      "relationships",
      "resources",
      "provenance",
      "intent",
      "events"
    ],
    "core-intent-knowledge": [
      "identity",
      "spaces",
      "assets",
      "points",
      "relationships",
      "resources",
      "provenance",
      "intent",
      "events",
      "knowledge"
    ],
    "full": [
      "identity",
      "spaces",
      "assets",
      "points",
      "relationships",
      "resources",
      "provenance",
      "intent",
      "events",
      "knowledge",
      "representation",
      "timeSeries"
    ]
  },
  "gradings": {
    "MUST": "Failure means the implementation does not conform at the claimed profile.",
    "SHOULD": "Failure is reported in the conformance statement but does not defeat conformance.",
    "INFO": "Measured and reported; no pass or fail."
  },
  "groups": [
    {
      "id": "PK",
      "title": "Package validity",
      "target": "package",
      "tests": [
        {
          "id": "PK-1",
          "grade": "MUST",
          "title": "Container form",
          "requirement": "BUS-1 16.2",
          "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."
        },
        {
          "id": "PK-2",
          "grade": "MUST",
          "title": "Manifest present and valid",
          "requirement": "BUS-1 16.3",
          "procedure": "Read manifest.json at the package root and validate against bus-manifest.schema.json.",
          "pass": "The manifest exists and validates with no errors."
        },
        {
          "id": "PK-3",
          "grade": "MUST",
          "title": "Document validity",
          "requirement": "BUS-1 17.4",
          "procedure": "Validate every file listed in manifest.documents against bus-document.schema.json.",
          "pass": "Every listed document exists and validates with no errors."
        },
        {
          "id": "PK-4",
          "grade": "MUST",
          "title": "Digest integrity",
          "requirement": "BUS-1 16.5",
          "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."
        },
        {
          "id": "PK-5",
          "grade": "MUST",
          "title": "No undeclared payload",
          "requirement": "BUS-1 16.4",
          "procedure": "Enumerate all archive entries.",
          "pass": "Every entry other than 'mimetype' and 'manifest.json' appears in manifest.documents or manifest.resources."
        },
        {
          "id": "PK-6",
          "grade": "MUST",
          "title": "Path safety",
          "requirement": "BUS-1 16.4",
          "procedure": "Inspect every archive entry name.",
          "pass": "No entry is absolute, contains a '..' segment, or resolves outside the package root."
        },
        {
          "id": "PK-7",
          "grade": "MUST",
          "title": "Identifier uniqueness",
          "requirement": "BUS-1 6.2",
          "procedure": "Collect every entity id in the package.",
          "pass": "No id occurs twice."
        },
        {
          "id": "PK-8",
          "grade": "MUST",
          "title": "Referential closure",
          "requirement": "BUS-1 9.2",
          "procedure": "Resolve every subject, object, deviceRef, targetOf, appliesToRef, scheduleRef and ChangeRecord subject.",
          "pass": "Every reference resolves to an entity present in the package, or to an entity explicitly declared external in the manifest."
        },
        {
          "id": "PK-9",
          "grade": "MUST",
          "title": "Extension declaration",
          "requirement": "BUS-1 15.3",
          "procedure": "Collect every namespace prefix used in type names, predicates and extension keys.",
          "pass": "Every non-bus prefix is declared in manifest.extensions."
        },
        {
          "id": "PK-10",
          "grade": "MUST",
          "title": "Completeness declaration",
          "requirement": "BUS-1 16.6",
          "procedure": "Inspect manifest.completeness.domains.",
          "pass": "All twelve substrate domains are present, and every domain in state partial or absent carries a reason."
        },
        {
          "id": "PK-11",
          "grade": "SHOULD",
          "title": "Profile support",
          "requirement": "BUS-1 2.3",
          "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."
        },
        {
          "id": "PK-12",
          "grade": "MUST",
          "title": "Property definition coverage",
          "requirement": "BUS-1 7.8",
          "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."
        },
        {
          "id": "PK-13",
          "grade": "MUST",
          "title": "Property value agrees with its definition",
          "requirement": "BUS-1 7.8",
          "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."
        },
        {
          "id": "PK-14",
          "grade": "MUST",
          "title": "Presentation referential integrity",
          "requirement": "BUS-1 13",
          "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."
        },
        {
          "id": "PK-15",
          "grade": "MUST",
          "title": "Actuation declaration is accurate",
          "requirement": "BUS-1 16.7",
          "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."
        },
        {
          "id": "PK-16",
          "grade": "MUST",
          "title": "Write bindings are well formed",
          "requirement": "BUS-1 13.7",
          "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."
        },
        {
          "id": "PK-17",
          "grade": "SHOULD",
          "title": "Drawing scale is checkable",
          "requirement": "BUS-1 13.3",
          "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."
        }
      ]
    },
    {
      "id": "RT",
      "title": "Round-trip reconstruction",
      "target": "roundTrip",
      "note": "Each test exports package A from the source system, imports A into the receiving system, re-exports package B from the receiving system, and compares A with B after canonicalization per BUS-1 14.5.",
      "tests": [
        {
          "id": "RT-1",
          "grade": "MUST",
          "title": "Identity preservation",
          "requirement": "BUS-1 6.4",
          "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."
        },
        {
          "id": "RT-2",
          "grade": "MUST",
          "title": "Object meaning",
          "requirement": "BUS-1 8",
          "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."
        },
        {
          "id": "RT-3",
          "grade": "MUST",
          "title": "Relationship graph",
          "requirement": "BUS-1 9",
          "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."
        },
        {
          "id": "RT-4",
          "grade": "MUST",
          "title": "Intent distinguishability",
          "requirement": "BUS-1 10",
          "profileFrom": "core-intent",
          "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."
        },
        {
          "id": "RT-5",
          "grade": "MUST",
          "title": "Provenance retention",
          "requirement": "BUS-1 14",
          "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."
        },
        {
          "id": "RT-6",
          "grade": "MUST",
          "title": "Unknown extension preservation",
          "requirement": "BUS-1 15.4",
          "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."
        },
        {
          "id": "RT-7",
          "grade": "MUST",
          "title": "Must-understand refusal",
          "requirement": "BUS-1 15.4",
          "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."
        },
        {
          "id": "RT-8",
          "grade": "MUST",
          "title": "Resource integrity",
          "requirement": "BUS-1 16.5",
          "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."
        },
        {
          "id": "RT-9",
          "grade": "MUST",
          "title": "Telemetry binding retention",
          "requirement": "BUS-1 8.6",
          "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."
        },
        {
          "id": "RT-10",
          "grade": "MUST",
          "title": "Knowledge retention",
          "requirement": "BUS-1 8.9",
          "profileFrom": "core-intent-knowledge",
          "procedure": "Compare every KnowledgeNote and its attachment relationship.",
          "pass": "Body text, noteKind, observedAt and the appliesTo relationship survive unaltered."
        },
        {
          "id": "RT-11",
          "grade": "MUST",
          "title": "Lifecycle continuity",
          "requirement": "BUS-1 9.3",
          "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."
        },
        {
          "id": "RT-12",
          "grade": "MUST",
          "title": "Omission honesty",
          "requirement": "BUS-1 16.6",
          "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."
        },
        {
          "id": "RT-13",
          "grade": "SHOULD",
          "title": "Idempotence",
          "requirement": "BUS-1 17.5",
          "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."
        },
        {
          "id": "RT-14",
          "grade": "INFO",
          "title": "Scale",
          "requirement": "BUS-1 16.4",
          "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."
        },
        {
          "id": "RT-15",
          "grade": "MUST",
          "title": "Binding preservation",
          "requirement": "BUS-1 13.6",
          "profileFrom": "full",
          "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."
        },
        {
          "id": "RT-16",
          "grade": "MUST",
          "title": "Command priority is not substituted",
          "requirement": "BUS-1 13.7",
          "profileFrom": "full",
          "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."
        },
        {
          "id": "RT-17",
          "grade": "MUST",
          "title": "Quality behavior preservation",
          "requirement": "BUS-1 13.6",
          "profileFrom": "full",
          "procedure": "Compare the quality block of every binding.",
          "pass": "staleAfter, onStale, onUnavailable and onOutOfService survive unchanged."
        },
        {
          "id": "RT-18",
          "grade": "MUST",
          "title": "Geometry fidelity",
          "requirement": "BUS-1 13.5",
          "profileFrom": "full",
          "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."
        },
        {
          "id": "RT-19",
          "grade": "MUST",
          "title": "Symbol role fallback",
          "requirement": "BUS-1 13.4",
          "profileFrom": "full",
          "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."
        },
        {
          "id": "RT-20",
          "grade": "MUST",
          "title": "Bespoke figure preservation",
          "requirement": "BUS-1 13.4",
          "profileFrom": "full",
          "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."
        },
        {
          "id": "RT-21",
          "grade": "MUST",
          "title": "Property definitions survive",
          "requirement": "BUS-1 7.8",
          "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."
        },
        {
          "id": "RT-22",
          "grade": "MUST",
          "title": "Alarm configuration survives",
          "requirement": "BUS-1 11",
          "profileFrom": "core-intent",
          "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."
        },
        {
          "id": "RT-23",
          "grade": "MUST",
          "title": "Events survive with their subjects",
          "requirement": "BUS-1 12",
          "profileFrom": "core-intent",
          "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."
        },
        {
          "id": "RT-24",
          "grade": "MUST",
          "title": "Revision continuity",
          "requirement": "BUS-1 6.6",
          "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."
        }
      ]
    },
    {
      "id": "IM",
      "title": "Importer behavior",
      "target": "importer",
      "tests": [
        {
          "id": "IM-1",
          "grade": "MUST",
          "title": "Rejects a corrupt digest",
          "requirement": "BUS-1 16.5",
          "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."
        },
        {
          "id": "IM-2",
          "grade": "MUST",
          "title": "Rejects an unknown major version",
          "requirement": "BUS-1 18.2",
          "procedure": "Present a package whose busVersion has a higher major number.",
          "pass": "The importer refuses and reports the version it supports."
        },
        {
          "id": "IM-3",
          "grade": "MUST",
          "title": "Accepts an unknown minor version",
          "requirement": "BUS-1 18.2",
          "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."
        },
        {
          "id": "IM-4",
          "grade": "MUST",
          "title": "Tolerates unknown enumeration members",
          "requirement": "BUS-1 18.3",
          "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."
        },
        {
          "id": "IM-5",
          "grade": "SHOULD",
          "title": "Reports a coverage summary",
          "requirement": "BUS-1 2.5",
          "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."
        },
        {
          "id": "IM-6",
          "grade": "MUST",
          "title": "Unknown symbol role degrades rather than fails",
          "requirement": "BUS-1 13.4",
          "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."
        },
        {
          "id": "IM-7",
          "grade": "MUST",
          "title": "Reports unenforceable actuation",
          "requirement": "BUS-1 13.7",
          "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."
        },
        {
          "id": "IM-8",
          "grade": "MUST",
          "title": "Refuses undefined properties",
          "requirement": "BUS-1 7.8",
          "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."
        }
      ]
    },
    {
      "id": "EX",
      "title": "Exporter behavior",
      "target": "exporter",
      "tests": [
        {
          "id": "EX-1",
          "grade": "MUST",
          "title": "Exports without a live vendor dependency",
          "requirement": "BUS-1 2.4",
          "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."
        },
        {
          "id": "EX-2",
          "grade": "MUST",
          "title": "Identifier stability across exports",
          "requirement": "BUS-1 6.4",
          "procedure": "Export the same building twice with no intervening change.",
          "pass": "Every entity id is identical in both exports."
        },
        {
          "id": "EX-3",
          "grade": "MUST",
          "title": "Identifier stability across change",
          "requirement": "BUS-1 6.4",
          "procedure": "Rename an asset, then export again.",
          "pass": "The id is unchanged and the rename appears as a ChangeRecord."
        },
        {
          "id": "EX-4",
          "grade": "MUST",
          "title": "Export is not narrower than operation",
          "requirement": "BUS-1 2.4",
          "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."
        },
        {
          "id": "EX-5",
          "grade": "SHOULD",
          "title": "Owner-initiated export",
          "requirement": "BUS-1 2.2",
          "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."
        },
        {
          "id": "EX-6",
          "grade": "MUST",
          "title": "Graphics export is unaided",
          "requirement": "BUS-1 2.4",
          "profileFrom": "full",
          "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."
        },
        {
          "id": "EX-7",
          "grade": "MUST",
          "title": "Property definitions are published, not invented per export",
          "requirement": "BUS-1 7.8",
          "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."
        }
      ]
    }
  ]
}
