|
| 1 | +# ADR-0001 — Canonical Artifact Identity |
| 2 | + |
| 3 | +## Status |
| 4 | + |
| 5 | +Accepted |
| 6 | + |
| 7 | +## Date |
| 8 | + |
| 9 | +2026-09-13 |
| 10 | + |
| 11 | +## Context |
| 12 | + |
| 13 | +DSL Core represents relationships between software engineering artifacts through the first-class ArtifactGraph model. |
| 14 | + |
| 15 | +Graph relations reference artifacts by identifier. The current WorkPackageGraph validator resolves artifact types from identifier prefixes such as: |
| 16 | + |
| 17 | +- `WP-` |
| 18 | +- `REQ-` |
| 19 | +- `ADR-` |
| 20 | +- `MS-` |
| 21 | + |
| 22 | +The current implementation contains a contract drift around artifact identity. |
| 23 | + |
| 24 | +The requirement profile defines `id` as a required field of the canonical RequirementAtom, while the TypeScript `RequirementAtom` interface currently does not expose an identifier. |
| 25 | + |
| 26 | +The runtime parser also supports requirement statements without an explicit artifact identifier. |
| 27 | + |
| 28 | +Before additional graph-addressable artifact types are introduced, DSL Core requires an explicit identity invariant. |
| 29 | + |
| 30 | +## Decision |
| 31 | + |
| 32 | +Every graph-addressable canonical artifact MUST have exactly one non-empty ArtifactId. |
| 33 | + |
| 34 | +An ArtifactId MUST uniquely identify exactly one artifact within the active canonical ArtifactGraph. |
| 35 | + |
| 36 | +Every graph relation source and target MUST resolve unambiguously to exactly one graph-addressable canonical artifact. |
| 37 | + |
| 38 | +ArtifactId identifies an artifact instance. |
| 39 | + |
| 40 | +ArtifactId MUST NOT be used as a substitute for: |
| 41 | + |
| 42 | +- ArtifactType |
| 43 | +- artifact revision or version |
| 44 | +- content digest |
| 45 | +- validation status |
| 46 | + |
| 47 | +ArtifactType and ArtifactId are independent concepts. |
| 48 | + |
| 49 | +Example: |
| 50 | + |
| 51 | + ArtifactType = RequirementAtom |
| 52 | + ArtifactId = REQ-001 |
| 53 | + |
| 54 | +Identifier prefixes such as `REQ-`, `ADR-`, `WP-` and `MS-` are part of the current type-resolution mechanism. Prefix-based type inference MUST NOT be treated as the definition of artifact identity itself. |
| 55 | + |
| 56 | +## Representation Boundary |
| 57 | + |
| 58 | +This decision establishes the identity invariant. |
| 59 | + |
| 60 | +It deliberately does not yet decide whether ArtifactId is represented: |
| 61 | + |
| 62 | +1. directly inside every canonical Atom, or |
| 63 | +2. in a common graph-addressable canonical artifact container. |
| 64 | + |
| 65 | +That representation decision MUST be made separately after the existing RequirementAtom, profile, parser and ArtifactGraph contracts have been reconciled. |
| 66 | + |
| 67 | +## Consequences |
| 68 | + |
| 69 | +New graph-addressable artifact types MUST define an unambiguous identity. |
| 70 | + |
| 71 | +Duplicate ArtifactIds inside one active canonical ArtifactGraph MUST be rejected. |
| 72 | + |
| 73 | +Empty ArtifactIds MUST be rejected for graph-addressable artifacts. |
| 74 | + |
| 75 | +Dangling relation targets MUST be rejected. |
| 76 | + |
| 77 | +Ambiguous relation targets MUST be rejected. |
| 78 | + |
| 79 | +Additional artifact types such as AcceptanceCriterionAtom MUST NOT be added until the existing canonical artifact identity contract drift has been resolved. |
| 80 | + |
| 81 | +## Existing Contract Drift |
| 82 | + |
| 83 | +At the time of this decision the following differences exist between the requirement profile and runtime representation: |
| 84 | + |
| 85 | +### Requirement profile |
| 86 | + |
| 87 | +The canonical model declares: |
| 88 | + |
| 89 | +- id — required |
| 90 | +- actor — required |
| 91 | +- subject — required |
| 92 | +- modality — required |
| 93 | +- action — required |
| 94 | + |
| 95 | +### RequirementAtom runtime type |
| 96 | + |
| 97 | +The TypeScript interface currently declares: |
| 98 | + |
| 99 | +- actor |
| 100 | +- modality |
| 101 | +- action |
| 102 | +- condition |
| 103 | +- result |
| 104 | + |
| 105 | +The runtime type currently does not declare: |
| 106 | + |
| 107 | +- id |
| 108 | +- subject |
| 109 | + |
| 110 | +The requirement profile currently represents negative modality as `must_not`, while the runtime type represents it as `must not`. |
| 111 | + |
| 112 | +The current generic requirement parser accepts requirement statements without an ArtifactId. |
| 113 | + |
| 114 | +These differences MUST be resolved explicitly and MUST NOT be hidden by the introduction of new artifact types. |
| 115 | + |
| 116 | +## Verification |
| 117 | + |
| 118 | +Implementation of this decision MUST preserve the existing green validation baseline. |
| 119 | + |
| 120 | +The following repository gates MUST remain successful: |
| 121 | + |
| 122 | + deno fmt --check |
| 123 | + deno lint |
| 124 | + deno test --allow-read --lock=deno.lock --frozen |
| 125 | + |
| 126 | +Future graph validation MUST provide deterministic tests for: |
| 127 | + |
| 128 | +- non-empty ArtifactId |
| 129 | +- ArtifactId uniqueness |
| 130 | +- relation target resolution |
| 131 | +- rejection of duplicate identifiers |
| 132 | +- rejection of dangling identifiers |
| 133 | +- preservation of existing requirement semantics |
0 commit comments