Skip to content

autoware_interface_spec_lint#

Config-driven static and manifest checks for the Autoware component interface specifications defined in autoware_component_interface_specs. This package gives fast, pre-build, human-readable diagnostics that complement the compile-time all_specs_valid<> static assertions: it catches "defined-but-unregistered" specs, version inconsistencies, cross-owner shadowing, heavy-raw topics that must not be versioned, and manifest drift that the compiler alone does not.

Each gate's severity comes from the committed gate config (config/interface_gates.yaml): off (not run), warn (advisory, prints findings but never fails), or error (fails the build when it reports at least one finding). Every implemented gate is set to error, so a finding now fails CI and the pre-commit hook; only the gates listed under "Honest deferrals" below are off. --warn-only overrides every gate to exit 0 for local advisory runs.

Gates#

Gate Input Severity Flags
interface_spec_concept domain headers error a struct with a name[] that is neither a valid topic (Message + depth + reliability + durability) nor a valid service (Service)
spec_registered domain headers error a spec struct not listed in its namespace's using Specs = std::tuple<...> (unless it carries the suppression marker)
version_consistency headers + manifest error a domain not declaring exactly one version{...}, or a manifest version that disagrees with the header version
qos_consistency headers + manifest error a registered spec whose history / depth / reliability / durability disagrees with its manifest qos block, is missing from the manifest, or names a QoS policy the manifest cannot express
manifest_fresh generator + committed JSON error the rebuilt generator output differs from the committed interface_manifest.json (see the binding-gate note below)
owner_isolation manifest(s) error a non-base-owner manifest entry whose interface name shadows a base-owner (autowarefoundation) entry
no_raw_spec_topic manifest(s) error a versioned topic whose interface name contains a heavy-raw deny substring; services are out of scope

The manifest audits (owner_isolation, no_raw_spec_topic) take a list of manifest dicts so a future vendor-partition manifest can be cross-checked against the base manifest; with the single committed core manifest owner_isolation is vacuously clean.

Binding manifest-freshness gate#

The lint's manifest_fresh can only bind where the manifest generator binary is available; on a plain checkout / pre-commit run it skips gracefully. The binding freshness gate is the specs-package gtest (autoware_component_interface_specs/test/test_manifest.cpp), which regenerates the manifest with the built generator and asserts byte-equality against the committed interface_manifest.json on every build-and-test CI run. Manifest drift is therefore a hard failure regardless of the advisory lint.

Honest deferrals#

The following design gate-table entries are declared off in the committed config and are intentionally deferred; enabling one is rejected by the config loader because there is no implementation to run yet.

Gate Why deferred
no_foreign_if_dependency needs per-component provided/required role manifests, which do not exist yet (they arrive with the deploy-time OCI-label manifest track)
profile_compat needs a vendor-specific interface profile that does not exist in this package yet; out of scope for this change
if_usage_coverage runtime gate; needs runtime introspection data this static-analysis package does not have, deferred to future work
admission_smoke runtime gate; needs runtime introspection data this static-analysis package does not have, deferred to future work

owner_isolation is wired and at error but binds only once a second (vendor-partition) manifest exists to cross-check against. Today the universe versioned surface is exactly the core re-exports (single version authority in core) and universe-owned specs are unversioned, so there is no separate universe-side gate wiring yet.

Suppression contract#

A spec struct is exempt from spec_registered when the marker // interface-spec-lint: not-versioned appears on the struct's own declaration line or on the line directly above it. Use it for a topic that is deliberately not part of the versioned interface set. The marker string is a fixed contract that other packages depend on, so do not change its text.

// interface-spec-lint: not-versioned
struct PointCloudMap {
  using Message = sensor_msgs::msg::PointCloud2;
  static constexpr char name[] = "/map/point_cloud_map";
  // ...
};

Usage#

# Lint the core specs with the committed gate config (severities from the config).
ament_autoware_interface_spec_lint

# Advisory local run: print findings but always exit 0.
ament_autoware_interface_spec_lint --warn-only

# Explicit paths and an alternate gate config.
ament_autoware_interface_spec_lint \
  --config common/autoware_interface_spec_lint/config/interface_gates.yaml \
  --spec-dir common/autoware_component_interface_specs/include/autoware/component_interface_specs \
  --manifest common/autoware_component_interface_specs/interface_manifest.json

manifest_fresh#

manifest_fresh needs the manifest generator binary. Point at it with --generator <path> or the INTERFACE_MANIFEST_GENERATOR environment variable. When neither is available the check skips gracefully (the binding gate is the specs-package gtest).

export INTERFACE_MANIFEST_GENERATOR=$PWD/build/autoware_component_interface_specs/generate_interface_manifest
ament_autoware_interface_spec_lint \
  --manifest common/autoware_component_interface_specs/interface_manifest.json \
  --generator "$INTERFACE_MANIFEST_GENERATOR"

Gate config#

config/interface_gates.yaml maps each gate to a severity and carries the no_raw_spec_topic deny/allow lists and the owner_isolation base owner. The loader rejects an unknown gate name and rejects enabling a deferred gate (it may only be declared off).