Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,29 @@ the lookup order in the project's `AGENTS.md`.
`skills/**/SKILL.md`, `features/`, and the toolkit's own contract text. Agents
resolve these from the toolkit at need.

### Schema change: the artifact validity axis

`metamodel/artifact.schema.yaml` gained a second lifecycle axis. `status` stays
the review axis — how confirmed an artifact is — and the new optional
`validity` (`active` | `retired`), with `retired_on`, `retired_reason`, and
`retired_note`, says whether the artifact still holds. A relation touching a
retired artifact keeps its reviewed status and is rendered as inactive rather
than dropped. The decision is ADR-009; the model is described in the metamodel
document.

For a project that vendored the schema:

- Re-copy `metamodel/artifact.schema.yaml` **and**
`scripts/validate-metamodel.rb` together. The validator reads the validity
vocabulary from the schema, exactly as it reads relation types from
`relations.schema.yaml`.
- The change is additive. Existing artifacts stay valid: an absent `validity`
means active, and nothing has to be backfilled.
- A new schema beside an old validator is the one combination to avoid: the
fields validate but nothing enforces the invariants, so a retired artifact
without `retired_on` passes unnoticed. An old schema beside a new validator is
safe — the validator falls back to its built-in vocabulary.

### Local skills and contracts extend, they do not duplicate

A consuming project may add its own `skills/**/SKILL.md` and task contracts for
Expand Down
57 changes: 56 additions & 1 deletion example/metamodel/artifact.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ properties:
minLength: 1
status:
type: string
description: Lifecycle state of the artifact.
description: >-
Review axis: how confirmed the artifact is. Whether it still holds is the
separate validity axis. 'superseded' and 'deprecated' are transitional
exceptions that still carry temporal meaning here; ADR-009 defers their
migration.
enum:
- draft
- proposed
Expand All @@ -51,6 +55,41 @@ properties:
- rejected
- superseded
- deprecated
validity:
type: string
description: >-
Temporal axis: whether the artifact still holds. An absent value means
active. The default below is a schema annotation and materializes
nothing, so validator and generator implement that reading explicitly.
enum:
- active
- retired
default: active
retired_on:
type: string
format: date
description: >-
Date of retirement. Required while validity is retired, rejected while
the artifact is active, and never earlier than created.
retired_reason:
type: string
description: >-
Machine-readable retirement reason, for filtering and generated views.
'no-longer-applicable' and 'removed' apply to every artifact type;
'mitigated' and 'materialized' apply to Risk artifacts only, which the
validator enforces.
enum:
- no-longer-applicable
- removed
- mitigated
- materialized
retired_note:
type: string
minLength: 1
description: >-
Free text explaining the retirement to a human reader. The reason is for
machines, the note is for people; neither replaces the other. Omit it
rather than leaving it empty.
owner:
type: string
minLength: 1
Expand Down Expand Up @@ -134,6 +173,22 @@ properties:
metadata_version:
type: string
default: "1.0"
allOf:
- if:
properties:
validity:
const: retired
required:
- validity
then:
required:
- retired_on
else:
properties:
retired_on: false
retired_reason: false
retired_note: false

examples:
- id: DOC-09001-adr-index
type: Document
Expand Down
15 changes: 15 additions & 0 deletions features/documentation-generation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ Feature: Documentation generation
When the metadata attribute fragment is rendered
Then it exposes the artifact id, status, and derived-from description as AsciiDoc attributes

Scenario: Impact fragment marks a relation to a retired artifact as inactive
Given an ADR whose outgoing relation points at a retired risk
When the impact fragment is rendered
Then the relation is still listed and marked inactive

Scenario: Traceability fragment marks the relations of a retired artifact as inactive
Given a retired risk with an incoming relation from an active ADR
When the traceability fragment is rendered for the retired risk
Then the incoming relation is still listed and marked inactive

Scenario: Traceability matrix marks an inactive relation
Given an ADR whose outgoing relation points at a retired risk
When the traceability matrix is rendered
Then the outgoing relation cell carries the inactive marker

Scenario: Chapter include fragment output is deterministic and sorted by artifact id
Given an arc42 chapter with two detail documents
When the chapter include fragment is rendered twice
Expand Down
40 changes: 40 additions & 0 deletions features/metamodel-validation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,46 @@ Feature: Metamodel validation
When the validator runs
Then it warns that a bidirectional relation was detected

Scenario: Artifact without validity is treated as active
Given an artifact that records no validity
When the validator runs
Then it reports no errors and the artifact counts as active

Scenario: Unknown validity value reports an error
Given an artifact whose validity is neither active nor retired
When the validator runs
Then it reports the unknown validity

Scenario: Retired artifact without a retirement date reports an error
Given a retired artifact that records no retirement date
When the validator runs
Then it reports that a retired artifact must record retired_on

Scenario: Retirement date before creation reports an error
Given a retired artifact whose retirement date precedes its creation date
When the validator runs
Then it reports that retired_on is earlier than created

Scenario: Active artifact carrying retirement fields reports an error
Given an active artifact that records a retirement date, reason, and note
When the validator runs
Then it reports that an active artifact must not record retirement fields

Scenario: Present but empty validity metadata reports an error
Given artifacts that declare validity or retirement fields with an empty or null value
When the validator runs
Then it reports each one instead of reading it as omitted

Scenario: Risk retirement reason on another artifact type reports an error
Given a retired document that claims the risk-specific reason mitigated
When the validator runs
Then it reports that the reason applies to Risk artifacts only

Scenario: Relation to a retired artifact warns and stays valid
Given an accepted relation pointing at a retired risk
When the validator runs
Then it reports no errors and warns that the relation points at a retired artifact

Scenario: Report states validation passed for valid artifacts
Given a directory of well-formed architecture artifacts
When the validator prints its report
Expand Down
57 changes: 56 additions & 1 deletion metamodel/artifact.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ properties:
minLength: 1
status:
type: string
description: Lifecycle state of the artifact.
description: >-
Review axis: how confirmed the artifact is. Whether it still holds is the
separate validity axis. 'superseded' and 'deprecated' are transitional
exceptions that still carry temporal meaning here; ADR-009 defers their
migration.
enum:
- draft
- proposed
Expand All @@ -51,6 +55,41 @@ properties:
- rejected
- superseded
- deprecated
validity:
type: string
description: >-
Temporal axis: whether the artifact still holds. An absent value means
active. The default below is a schema annotation and materializes
nothing, so validator and generator implement that reading explicitly.
enum:
- active
- retired
default: active
retired_on:
type: string
format: date
description: >-
Date of retirement. Required while validity is retired, rejected while
the artifact is active, and never earlier than created.
retired_reason:
type: string
description: >-
Machine-readable retirement reason, for filtering and generated views.
'no-longer-applicable' and 'removed' apply to every artifact type;
'mitigated' and 'materialized' apply to Risk artifacts only, which the
validator enforces.
enum:
- no-longer-applicable
- removed
- mitigated
- materialized
retired_note:
type: string
minLength: 1
description: >-
Free text explaining the retirement to a human reader. The reason is for
machines, the note is for people; neither replaces the other. Omit it
rather than leaving it empty.
owner:
type: string
minLength: 1
Expand Down Expand Up @@ -134,6 +173,22 @@ properties:
metadata_version:
type: string
default: "1.0"
allOf:
- if:
properties:
validity:
const: retired
required:
- validity
then:
required:
- retired_on
else:
properties:
retired_on: false
retired_reason: false
retired_note: false

examples:
- id: DOC-09001-adr-index
type: Document
Expand Down
Loading
Loading