---
id: OBPI-0.0.43-02-dm-artifact-schema-template
parent: ADR-0.0.43
item: 2
lane: Heavy
status: Draft
---

# OBPI-0.0.43-02-dm-artifact-schema-template: DM tactical artifact + schema + template

## ADR Item

- **Source ADR:** `docs/design/adr/foundation/ADR-0.0.43-ddd-domain-cascade/ADR-0.0.43-ddd-domain-cascade.md`
- **Checklist Item:** #2 — "DM artifact + schema + template — New artifact type at `docs/design/domain/DM-<bc-slug>.md`; `DomainModel` Pydantic model with `Aggregate` / `Entity` / `ValueObject` / `DomainEvent` / `ImplementationSurface` / `InboundContract` / `OutboundContract`; `src/gzkit/schemas/domain_model.json`; template file; Aggregates + Implementation Surface required, rest optional."

**Status:** Draft

## Objective

Introduce a new tactical-DDD artifact type `docs/design/domain/DM-<bc-slug>.md` — one per bounded context — with the full Evans tactical vocabulary backed by Pydantic models and JSON Schema. Aggregates and Implementation Surface are required; Entities, Value Objects, Domain Events, and Open Questions are optional. The Implementation Surface declaration is the load-bearing input for OBPI-11's AST cross-context import enforcer.

## Lane

**Heavy** — introduces a new artifact type (DM) with a new canonical directory contract (`docs/design/domain/`), new Pydantic models in the public governance surface, a new JSON Schema, and a new template file.

## Allowed Paths

- `src/gzkit/governance/domain_models.py` — EXTEND (OBPI-01 created); add `DomainModel`, `Aggregate`, `Entity`, `ValueObject`, `DomainEvent`, `ImplementationSurface`, `InboundContract`, `OutboundContract`
- `src/gzkit/schemas/domain_model.json` — NEW
- `src/gzkit/templates/dm.md` — NEW
- `docs/design/domain/.gitkeep` — NEW
- `tests/governance/domain/test_dm_models.py` — NEW
- `tests/governance/domain/test_dm_schema.py` — NEW
- `tests/governance/domain/test_dm_template_parse.py` — NEW

## Denied Paths

- `src/gzkit/governance/domain_models.py::UbiquitousLanguageTerm,BoundedContextDeclaration,ContextMapEntry,RelationType` — OBPI-01 owns the strategic surface
- `src/gzkit/schemas/glossary_term.json`, `bounded_context.json`, `context_map_entry.json` — OBPI-01
- `src/gzkit/schemas/legacy_mapping.json` — OBPI-07
- `src/gzkit/schemas/adr.json`, `ghi.json`, `obpi.json` — OBPI-04
- `src/gzkit/cli/**` — OBPI-03 / OBPI-01
- `src/gzkit/governance/trust_audits/domain_cascade.py` — OBPI-06
- `src/gzkit/governance/cascade_import_check.py` — OBPI-11
- `src/gzkit/ledger/**` — OBPI-05
- Any `docs/design/domain/DM-<slug>.md` content file (this OBPI lands template, not authored DMs)
- `docs/design/prd/PRD-GZKIT-1.0.0.md` — OBPI-13
- Runtime dependencies, lockfiles, CI

## Requirements (FAIL-CLOSED)

1. **REQUIREMENT (`DomainModel` root).** Pydantic class with `bc_slug: str` (matches `^[a-z][a-z0-9-]*$`), `parent_prd: str`, `owner_persona: str`, `lifecycle_state: Literal["active", "deprecated", "retired"]`, `glossary_specializations: list[UbiquitousLanguageTerm]`, `aggregates: list[Aggregate]` (≥1), `entities: list[Entity] = []`, `value_objects: list[ValueObject] = []`, `domain_events: list[DomainEvent] = []`, `implementation_surface: ImplementationSurface` (required), `inbound_contracts: list[InboundContract] = []`, `outbound_contracts: list[OutboundContract] = []`, `open_questions: list[str] = []`, `decision_history: list[str] = []` (auto-populated, Layer-3-within-Layer-1). `extra="forbid"`.
2. **REQUIREMENT (`Aggregate`).** Pydantic class with `name: str` (PascalCase), `root_entity: str`, `invariants: list[str]` (≥1), `transactional_boundary: str` (one-sentence). `extra="forbid"`.
3. **REQUIREMENT (`ImplementationSurface`).** Pydantic class with `paths: list[str]` (Python module paths or globs), `notes: str = ""`. Empty `paths` valid (signals "no code surface yet"). OBPI-11's AST enforcer reads from `paths`.
4. **REQUIREMENT (`InboundContract` / `OutboundContract`).** Pydantic class with `other_bc: str`, `relationship_type: RelationType`, `description: str` (≥10 words), `pinned_terms: list[str] = []`. `extra="forbid"`. MUST be reflected in PRD § 2.3 (OBPI-06 enforces consistency).
5. **REQUIREMENT (`Entity` / `ValueObject` / `DomainEvent`).** Each Pydantic class with `name: str`, `fields: dict[str, str]`, `notes: str = ""`. Optional in `DomainModel`. `extra="forbid"`.
6. **REQUIREMENT (DM template).** `src/gzkit/templates/dm.md` scaffolds: frontmatter, required sections (`## Identity`, `## Glossary Specializations`, `## Aggregates`, `## Implementation Surface`, `## Inbound Contracts`, `## Outbound Contracts`), optional sections commented out (`<!-- ## Entities -->`, `<!-- ## Value Objects -->`, `<!-- ## Domain Events -->`, `<!-- ## Open Questions -->`), and `## Decision History` with `<!-- AUTO-GENERATED by gz domain regenerate; DO NOT EDIT -->` marker.
7. **REQUIREMENT (JSON Schema).** `src/gzkit/schemas/domain_model.json` validates full `DomainModel` with `"additionalProperties": false` throughout.
8. **REQUIREMENT (directory contract).** `docs/design/domain/.gitkeep` exists; directory is precondition for every downstream OBPI consuming DMs.
9. **REQUIREMENT (no downstream coupling).** Nothing here may presuppose CLI (OBPI-03), validator (OBPI-06), or AST enforcer (OBPI-11). DM schema/template MUST be parseable standalone.

> STOP-on-BLOCKERS: if `RelationType` cannot be imported cleanly from `domain_models.py` (circular-import risk between `Aggregate` and `InboundContract`), halt and surface; never duplicate the enum.

## Discovery Checklist

**Parent ADR:**

- [ ] **Parent ADR § Decision item #2 — quote verbatim** into Implementation Summary
- [ ] Parent ADR § Intent
- [ ] Parent ADR file

**Governance:**

- [ ] `AGENTS.md` § Lane Rules
- [ ] `.gzkit/rules/models.md` — Pydantic doctrine
- [ ] `docs/governance/state-doctrine.md` — Layer-1/3 separation (DM is Layer 1; § Decision History is Layer-3-within-Layer-1 carve-out)

**Context:**

- [ ] OBPI-0.0.43-01 strategic models landed
- [ ] Existing artifact templates in `src/gzkit/templates/`
- [ ] Existing schemas in `src/gzkit/schemas/`

**Prerequisites:**

- [ ] OBPI-0.0.43-01 complete (strategic Pydantic surface importable)
- [ ] `src/gzkit/templates/` exists

**Existing Code:**

- [ ] `src/gzkit/governance/domain_models.py` (OBPI-01 product)
- [ ] Existing templates (PRD, ADR, OBPI) reviewed for conventions

## Quality Gates

### Gate 1: ADR

- [ ] Parent ADR checklist item #2 quoted
- [ ] Intent recorded

### Gate 2: TDD

- [ ] `DomainModel` tests: (a) valid minimal DM (b) missing `aggregates` rejected (c) missing `implementation_surface` rejected (d) extra field rejected (e) `decision_history` round-trips
- [ ] `Aggregate` tests: ≥1 invariant required; PascalCase enforcement; extra field rejected
- [ ] `InboundContract` / `OutboundContract` tests: relationship-type enum + word-count description
- [ ] JSON Schema round-trip test
- [ ] Template parse test: scaffolded DM with stub content parses against schema
- [ ] Tests pass: `uv run gz test`

### Code Quality

- [ ] Lint / typecheck clean

### Gate 3: Docs (Heavy only)

- [ ] mkdocs build --strict clean
- [ ] No manpages required (OBPI-12 authors cascade doctrine page)

### Gate 4: BDD (Heavy only)

- [ ] No new BDD scenarios required

### Gate 5: Human (Heavy + Foundation)

- [ ] Attestation recorded

## Verification

```bash
uv run gz validate --documents
uv run gz lint
uv run gz typecheck
uv run gz test

test -f src/gzkit/schemas/domain_model.json
test -f src/gzkit/templates/dm.md
test -d docs/design/domain
test -f docs/design/domain/.gitkeep
uv run python -c "from gzkit.governance.domain_models import DomainModel, Aggregate, Entity, ValueObject, DomainEvent, ImplementationSurface, InboundContract, OutboundContract; print('imports OK')"
uv run -m unittest tests.governance.domain.test_dm_models tests.governance.domain.test_dm_schema tests.governance.domain.test_dm_template_parse -v
```

## Demo

```bash
# Scaffold a DM from the template and validate it round-trips
cp src/gzkit/templates/dm.md /tmp/DM-demo.md
uv run python -c "
from gzkit.governance.domain_models import DomainModel, Aggregate, ImplementationSurface
dm = DomainModel(
    bc_slug='demo-bc',
    parent_prd='PRD-GZKIT-1.0.0',
    owner_persona='main-session',
    lifecycle_state='active',
    glossary_specializations=[],
    aggregates=[Aggregate(name='DemoAggregate', root_entity='DemoRoot', invariants=['Demo invariant holds.'], transactional_boundary='All demo state changes atomically.')],
    implementation_surface=ImplementationSurface(paths=[], notes='No code surface yet.'),
)
print(dm.model_dump_json(indent=2))
"
rm /tmp/DM-demo.md
```

## Acceptance Criteria

- [ ] REQ-0.0.43-02-01: Given `DomainModel`, when constructed with `aggregates=[]`, then `ValidationError` raised
- [ ] REQ-0.0.43-02-02: Given `DomainModel`, when `implementation_surface` is omitted, then `ValidationError` raised
- [ ] REQ-0.0.43-02-03: Given `Aggregate`, when `invariants=[]`, then `ValidationError` raised
- [ ] REQ-0.0.43-02-04: Given `Aggregate`, when `name` is not PascalCase, then `ValidationError` raised
- [ ] REQ-0.0.43-02-05: Given `InboundContract` / `OutboundContract`, when `description` has <10 words, then `ValidationError` raised
- [ ] REQ-0.0.43-02-06: Given `InboundContract` / `OutboundContract`, when `relationship_type` is outside `RelationType` enum, then `ValidationError` raised
- [ ] REQ-0.0.43-02-07: Given `src/gzkit/schemas/domain_model.json`, when valid `DomainModel` instance validated, then passes; with unknown field, fails
- [ ] REQ-0.0.43-02-08: Given `src/gzkit/templates/dm.md`, when inspected, then required section headers present and optional sections present as HTML-comment hints
- [ ] REQ-0.0.43-02-09: Given `docs/design/domain/`, when inspected post-OBPI, then `.gitkeep` exists
- [ ] REQ-0.0.43-02-10: Given `## Decision History` section in template, when inspected, then `<!-- AUTO-GENERATED by gz domain regenerate; DO NOT EDIT -->` marker present

## Completion Checklist

- [ ] **Gate 1 (ADR):** Intent recorded
- [ ] **Gate 2 (TDD):** RGR followed
- [ ] **Code Quality:** Clean
- [ ] **Gate 3 (Docs):** mkdocs clean
- [ ] **Gate 5 (Human):** Attestation recorded
- [ ] **OBPI Acceptance:** Evidence recorded below

## Evidence

### Gate 1 (ADR)

- [ ] Intent recorded

### Gate 2 (TDD)

```text
# Paste test output here
```

### Code Quality

```text
# Paste lint/typecheck output here
```

### Gate 3 (Docs)

```text
# Paste mkdocs output here
```

### Gate 4 (BDD)

```text
# N/A
```

### Gate 5 (Human)

```text
# Record attestation text here
```

### Value Narrative

### Key Proof

### Implementation Summary

- Files created/modified:
- Tests added:
- Date completed:
- Attestation status:
- Defects noted:

## Tracked Defects

_No defects tracked._

## Human Attestation

- Attestor: `<name>` when required, otherwise `n/a`
- Attestation: substantive attestation text or `n/a`
- Date: YYYY-MM-DD or `n/a`

---

**Brief Status:** Draft

**Date Completed:** -

**Evidence Hash:** -
