Descriptions, Comments, and Annotations

Configuration files can carry meta-data next to the values. Text for humans and typed annotations defined by the definition.

Descriptions and Comments

Every entity, struct, and parameter (in its object form) accepts two free text keys:

  • $description describes the element itself, for example what a specific sensor instance measures. Think of it as documentation that belongs to the data. It is like Javadoc or Doxygen.

  • $comment explains a decision, for example why a value deviates from the usual choice.

sampleTime: {
    value: 50,
    $comment: "Reduced for the oil temperature plausibility check.",
    $description: "Sample Time \n\n\
    * Markdown \n\
    * Support"
},

Both are part of the model and they survive merging and appear in the exported merged configuration. A plain JSON5 // comment does not. It lives only in the source file. Use // comments for notes to the next editor of the file, and $description/$comment for information that should travel with the data.

$description supports Markdown. A multiline $description is indent-normalized: the common leading indentation and a single leading or trailing blank line are removed, so the text can be indented to match the JSON nesting without the indentation appearing in the rendered documentation. JSON5 has no raw multiline strings, so write each line as …​\n\ (a \n escape followed by a line continuation).

Typed Annotations

A definition can declare annotation types, which are structured, validated metadata you attach to configuration elements. The PumpControl definition declares a Requirement annotation for tracing values to safety requirements:

annotationTypes: [
    {
        typeName: "Requirement",
        title: "Requirement trace",
        description: "Links an element to the safety requirements it implements.",
        targets: [
            "All"
        ],
        retention: "Output",
        annotation: {
            ids: {
                typeName: "Id",
                multiplicity: "1..*",
                description: "Requirement identifiers.",
                string: {
                    pattern: "^REQ-[0-9]+$"
                }
            }
        }
    }
]

In the configuration, the annotation key is the type name in lowerCamelCase with a leading underscore, and its content is validated like any other element, here including the REQ- pattern:

{
    $definition: "PumpControl@1.0",
    pump: {
        name: "MainPump",
        maxCurrent: 8500,
        _requirement: {
            ids: [
                "REQ-4711"
            ]
        }
    }
}
  • Definitions define which annotations exist, and what fields they have. Completion offers the available _…​ keys.

  • The definition also restricts where an annotation may appear (its targets), for example only on entities. Attaching it elsewhere is an error.

  • An annotation whose type has exactly one required field also accepts the bare value instead of the object form, for example _owner: "body-team".

Use typed annotations for anything a tool later consumes like requirement tracing, review status.

Confµgami Built-in Annotations

Only _origin and _acceptConstraintViolation appear in a configuration file, the other annotations are definition-side and are described in Confµgami Built-in Annotations of the developer manual.

Accepting a Constraint Violation

_acceptConstraintViolation: ["PriorityLimit"] on an element accepts its violation of the constraint PriorityLimit. An accepted error stays visible as a warning, an accepted warning or info disappears. Add an optional reason to record why. See Accepting a Violation.

Origin Annotation

cfu cfg export-merged --with-origin attaches an _origin to every element of the merged output, naming the file and the line the value came from. That is the fastest answer to "who set this?" in a stack of merged files, see Working with Multiple Files.

Since a scalar cannot carry an annotation, the export writes such a parameter in its object form:

timeoutMs: {
    _origin: [ "FileA:11:9" ],
    value: 250,
}

After a merge an element has more than one source, and the array then runs from the weakest to the strongest one, so the last entry is the file that won.

The entries reference a $originSpec table at the top of the file that maps the short file ids to real paths. You can also write _origin by hand, to record that a file was produced from some other source outside Confµgami. Such an annotation is data of your file: Confµgami keeps it and does not overwrite it with its own trace.

The full format is specified in Origin Annotations.