Skip to main content

The Feature Manifest

The feature manifest is the file you edit to curate the feature model. This page explains what it decides, what the pipeline derives on its own, how the manifest is structured, and how the pipeline reads it. Read it before your first change to the manifest.

What the manifest decides​

The manifest holds modeling judgments, the decisions that code cannot express:

  • which Artemis modules become features, and which feature-shaped modules deliberately stay out, and why;
  • which technical features exist, such as the database and the CI provider;
  • where each feature sits in the tree, and in which order;
  • whether a feature is mandatory, and its default state when the Artemis default does not fit;
  • constraints between features, and relations that deliberately stay unenforced;
  • configuration keys that the pipeline cannot find or classify on its own.

Everything else comes from Artemis. The pipeline reads the names and descriptions of modules from the Artemis English translations, their default states from the Artemis configuration, and the keys each module reads from its guarded source files. When the manifest and Artemis both describe something, the manifest wins.

What the pipeline derives​

The pipeline fills in the parts that follow from the source or from the manifest itself:

Derived partSource
The anchor of a functional featureThe feature id: the entry fileupload anchors module:fileupload
The root artemisImplied when no conceptual node declares a root
The excludes constraints of an alternative groupOne constraint for every pair of children
The configuration mappings of a featureThe keys its guarded source files read, see Curation and Conformance
The Compose file of a database featureThe Compose files the scan finds for the infra: anchor
The SPRING_PROFILES_ACTIVE value of a profile featureThe profile name of the anchor, or the profiles list
The required capabilities of a functional featureIts deployment inputs: <id>-service when one is not a secret, <id>-secret when one is

Because these parts are derived, a change in Artemis reaches the model without a manifest edit. When Artemis moves its Compose files, for example, the derived Compose paths follow.

Where it lives​

The manifest lives in this repository at src/main/resources/feature-model/extraction/artemis-feature-manifest.yml. The property featureManifestSource in gradle.properties selects where the pipeline reads it from:

ValueSource
repositoryThe file in this repository
checkoutsupportingFiles/feature-model/artemis-feature-manifest.yml inside the Artemis checkout

The checkout mode exists for the manifest cutover, which moves the manifest into Artemis so that a feature and its curation change together. In repository mode, the pipeline also looks at the Artemis path: when a copy exists there, it must be byte-identical to the file in this repository, or the run fails.

Structure​

The manifest has six lists below its version:

manifestVersion: 5
features: [] # Artemis modules that become functional features
technical: [] # maintainer-only features with an infra: or profile: anchor
notModeled: [] # feature-shaped modules that stay out, with a reason
conceptualNodes: [] # features without an anchor: the groups and the core modules
constraints: [] # requires and excludes rules between features
ignoredRelations: [] # relation candidates that deliberately stay unenforced

Write every entry as a block, and separate entries with a blank line. Each list starts with a comment that says what it holds.

The pipeline reads the file strictly. An unknown field, a wrong value, or a reference to an undeclared parent stops the run with a message that names the entry.

Features​

A features entry turns an Artemis module into a functional feature. Its id is the Artemis module id:

- id: athena
group: assessment-and-integrity
order: 3

Most fields are optional:

FieldMeaning
group or parentWhere the feature sits in the tree
orderPosition among its siblings
optionalitymandatory or optional; features are optional by default
defaultStateenabled or disabled; without it, the Artemis default applies
configurationConfiguration keys the pipeline cannot find or classify on its own, see below
name, description, documentationUrlOverride the texts that the pipeline takes from Artemis
rationaleWhy the feature is modeled this way

Configuration entries​

The pipeline finds most configuration keys of a feature on its own. A configuration entry handles the rest:

configuration:
- key: spring.ai.openai.api-key
secret: true

An entry adds or confirms a key as a deployment input. secret: true marks its value as a secret, which the deployment packages only ever write as a ${VARIABLE} placeholder. action: exclude rejects a key that the pipeline derived but that does not belong to the feature. Write a comment above the list that says why the pipeline cannot see the key.

Technical features​

A technical entry declares a maintainer-only feature. It names its candidate in anchor:

- anchor: profile:localci
id: integrated-code-lifecycle
group: ci-provider
defaultState: enabled
order: 1
profiles: [localci, buildagent]
name: Integrated Code Lifecycle
description: Built-in CI provider activated by the localci and buildagent Spring profiles.

The fields are the same as for a features entry. profiles lists the Spring profiles the feature activates when the profile name of the anchor alone is not enough. The pipeline derives the Compose file of an infra: anchor and the SPRING_PROFILES_ACTIVE value of a profile: anchor. When it cannot, the run fails with TECHNICAL_MAPPING_UNDERIVABLE.

Technical features are for maintainers only; the guided workflow never shows them to teachers.

Not modeled​

A notModeled entry keeps a module out of the model:

- anchor: module:passkey-admin
reason: sub-option
rationale: Administrator reauthentication policy within passkey support, not an independent feature.

Only modules that Artemis presents as features need a decision: the modules the server enumerates or the admin page shows. Every other candidate without an entry, such as a runtime toggle or a Spring profile, stays out of the model and appears as info in the report. You can still list such a candidate here to record why it stays out.

The reason is a short code that groups exclusions in the report. The manifest uses deferred, sub-option, internal-mechanism, operational, and experimental. Without a reason, the entry counts as unspecified and the report shows a warning. Write a rationale for every runtime toggle you list; the report warns when one is missing.

Conceptual nodes and the technical subtree​

Conceptual nodes are features without an anchor. They give the tree its groups and the mandatory core modules:

- id: database
parent: artemis
kind: group
category: technical
groupType: alternative
order: 6
name: Database

A group with groupType: alternative lets a deployment choose exactly one child. The pipeline derives one excludes constraint for every pair of its children. The technical subtree uses this for the database (mysql or postgresql) and the CI provider (integrated-code-lifecycle or jenkins).

Constraints and ignored relations​

A constraint is a rule between two features:

- id: apollon-requires-modeling
type: requires
source: apollon
target: modeling

The type is requires or excludes. Do not declare the exclusions of an alternative group: the pipeline derives them, and a declared duplicate is dropped with the warning MANIFEST_CONSTRAINT_REDUNDANT.

When the scan finds a relation candidate between two modeled features, the manifest must decide about it: declare a constraint, or record it under ignoredRelations with a rationale that says why the relation stays unenforced.

Schema version​

The manifest declares manifestVersion: 5. The pipeline rejects every other version. It also rejects sections and fields that the pipeline derives or that live elsewhere, with a message that says what to do instead. Examples are include, exclude, and renames, the fields artifactMappings and requiresCapabilities, and artemisCommitSha: the source revision comes from the checkout, and the runtime image reference lives in delivery/artemis-runtime-image.json.

Search documentation